2017-11-07 4 views
1

다른 질문을봤을 때 Python의 단위 테스트를하는 데 어려움을 겪고 있습니다. 노력 2 일 및 나는 진전을 보이지 않았다.Python Unit Test Mocking

클래스의 일부인 내 메서드에는 DAL에 대한 호출이 몇 가지 있습니다.

car_registration = self.dal.cars.get_by_registration('121D121') 

이 DAL은 기본 클래스에서 구성됩니다. 단위 테스트를 실행할 때이 호출을 완전히 무시/모의하고 대신 미리 정의 된 응답을 반환하여 메서드를 계속 진행하고 모든 것이 예상대로 작동하는지 확인합니다.

방법으로의 시작 : 순간

def change_registration(self): 

    body = json.loads(self.request.body) 
    registration = body['registration'] 
    car = self.dal.cars.get_by_registration(registration) 

내 파이썬 테스트 파일은 다음과 같습니다 나는 그러나 응답 (3)을 얻을 것으로 기대하고있다

class CarTestCase(unittest.TestCase): 
    def setUp(self): 
     self.car_controller = CarController() 


    def test_change_registrations(self): 
     self.car_controller.dal.cars.get_by_registration = MagicMock(return_value=3) 
     response = self.car_controller.change_registration() 

오류가 발생되고있다.

조롱이 작동하지 않고 유닛 테스트를 사용할 때 완전히 설정되지 않은 주 DAL을 계속 사용하려고합니다. 실제 DAL을 찾지 않고 대신 mock을 찾는 것을 어떻게 막을 수 있습니까?

+0

난 당신이'dal' 속성을 조롱 할 필요가 가정 그 자체. 'self.car_controller.dal = Mock()'과 같은 것. 그렇다면'self.car_controller.dal.cars.get_by_registration.return_value = 3'. – chepner

+0

그 라인을 변경하면 'AttributeError : 속성을 설정할 수 없습니다'라는 메시지가 나타납니다. – user7692855

답변

1

난 당신이 우리에게 당신의 전략 아무 문제가 없기 때문에 오류를 트리거 코드를 표시되지 않는 생각 : 여기

시험의 일부 변화와 완벽한 예입니다. 코드를 모방 상상력을 사용하여 우리는 내가이 쓸 수없는 그것은 문제없이 실행 :

여기
import unittest 
from unittest.mock import MagicMock 

class CarList(): 
    def get_by_registration(self, registration): 
     pass 

class Dal: 
    def __init__(self): 
     self.cars = CarList() 
    pass 

class CarController: 

    def __init__(self): 
     self.dal = Dal() 

    def change_registration(self): 
     registration = None 
     car = self.dal.cars.get_by_registration(registration) 
     return car 

class CarTestCase(unittest.TestCase): 
    def setUp(self): 
     self.car_controller = CarController() 


    def test_change_registrations(self): 
     self.car_controller.dal.cars.get_by_registration =\ 
      MagicMock(return_value=3) 
     result = self.car_controller.change_registration() 
     self.assertEqual(result, 3) 

unittest.main() 
0

개인 의견 : 저는 간단하게 시작할 것을 제안합니다. 비 마법적인 방법으로 당신을 제공하는 것을 이해하면 '마법'을 사용하십시오. 비 매직 솔루션을 사용하는 것이 이해하기 쉽습니다.

나는 여러 가지 간단한 해결책을 갖고 있다고 생각합니다. 대신에, 달성하려고 무엇을 위해 :

self.car_controller.dal.cars.get_by_registration = MagicMock(return_value=3) 

당신은 시도 할 수 :

self.car_controller.dal.cars.get_by_registration = lambda: 3 

을하지만 당신이 언급 한 모든 방법을 대체 할 수 있습니다. 사실 나는 '단순한'의존성 주입을 고려할 것이다. 테스트하기가 어렵다면 다른 디자인이 더 좋을 것이라는 징표 일 수도 있습니다 (TDD - 테스트 주도 디자인의 아이디어). 간단한 의존성 주입은 예를 들어 dal을 생성자 CarController에 전달하는 것입니다.

from unittest import TestCase 
from unittest.mock import Mock 

class SomeDal(object): 
    def get_something(self): 
     return 'something' 

class SomeController(object): 
    def __init__(self, dal): 
     self.dal = dal 

    def upper_something(self): 
     return self.dal.get_something().upper() 

class TestSomeController(TestCase): 
    def test_using_simple_patch(self): 
     controller = SomeController(SomeDal()) 
     controller.dal.get_something = lambda: 'anything' 
     assert controller.upper_something() == 'ANYTHING' 

    def test_using_simple_patch_and_injection(self): 
     dal = SomeDal() 
     dal.get_something = lambda: 'anything' 
     controller = SomeController(dal) 
     assert controller.upper_something() == 'ANYTHING' 

    def test_using_simple_mock_class(self): 
     class MockDal(object): 
      def get_something(self): 
       return 'anything' 
     controller = SomeController(MockDal()) 
     assert controller.upper_something() == 'ANYTHING' 

    def test_using_semi_magic_mock(self): 
     mock_dal = Mock(spec=SomeDal) 
     mock_dal.get_something.return_value = 'anything' 
     controller = SomeController(mock_dal) 
     assert controller.upper_something() == 'ANYTHING' 
+0

MagicMock을 사용하는 유일한 이유는 온라인에서 예제를 발견했기 때문입니다. 나는 아직도 내가 어떻게해야하는지에 관해서는 매우 혼란 스럽다. 나는 자기가 있어야하는지 잘 모르겠습니다. 왜냐하면 CarController 클래스의 멤버이고 테스트 클래스가 아니기 때문입니다. – user7692855

+0

예, 인터넷에 많은 예제가 있습니다. 몇 가지 간단한 예제를 추가하여 아이디어를 제공합니다. BTW 나는 상속의 필요성이없는'unittest'보다'pytest'를 선호합니다. 그러나 그것은 사소한 세부 사항입니다. 나는 Mock이나 MagicMock을 사용하지 말라는 것이 아니다. 그러나 왜 사용해야하는지 이해할 때 사용하십시오. – de1

+0

TestCase 클래스 내부에서 self를 사용하면 TestCase가 아닌 CarController를 조롱하는 것처럼 보일 수 있지만 self.car_controller를 작성하면 CarController 객체에 대한 참조이므로 아무런 문제가 없습니다. – progmatico

0

내 예 :

# test_tool_file.py 
import unittest 

from unittest.mock import patch, Mock, call 

import test_tools_file 

class MyObject(): 
    def __init__(self, data): 
     self.data = data 

    def get_data(self): 
     return self.data 

    def count(self): 
     return len(self.get_data()) 

class TestFile(unittest.TestCase): 
    """ Cas de tests. 
    """ 
    @patch("test_tools_file.MyObject.get_data") 
    def test_1(self, mock_get): 
     """ test_1 
     """ 
     mock_get.return_value = [1,2,3,4,5,6] 

     obj = MyObject(["12", "13"]) 

     result = obj.count() 

     self.assertEqual(result, 6)