Pydantic (BaseModel) - 如何模拟 (pytest/unittest/mockito)?
Pydantic (BaseModel) - How to mock (pytest/unittest/mockito)?
我正在进行单元测试(基本上使用 pytest/unittest/mockito),我需要模拟使用 Pydantic (BaseModel) 实现的 class 的实例化。显然,如果不传递有效的有效数据,就不可能在这些情况下模拟 class。我不能使用“ANY()”,因为会发生错误。有什么方法可以模拟这个 class 而不必使用有效数据作为参数吗?
注意:显然问题的发生是因为正在使用 Pydantic。
我已经在 Internet 上进行了大量研究,但没有成功...有什么想法吗?
下面是我在测试中使用的非常简单的代码...
pydantic_class.py - Pydantic(基础模型)Class
from pydantic import BaseModel
from some.path.sometypea import SomeTypeA
from some.path.sometypeb import SomeTypeB
class PydanticBaseModel(BaseModel):
someInt: int
someStr: str
someTypeA: SomeTypeA
someTypeB: SomeTypeB
code_to_test.py - 要测试的代码
from some.path.pydantic_class import PydanticBaseModel
class ClassToTest():
def test_method(self)
pydantic_base_model = PydanticBaseModel(
someInt=0,
someStr="value",
someTypeA=<SomeTypeAObj>,
someTypeB=<SomeTypeBObj>
)
[...]
test_code.py - 测试代码
import unittest
from mockito import ANY, when
class SomeTypeTest(unittest.TestCase):
def test_sometype_method(self):
when(PydanticBaseModel(
someInt=ANY(),
someStr=ANY(),
someTypeA=ANY(),
someTypeB=ANY()
)).thenReturn(None)
[...]
测试输出(简体)
(test-project) [username@username-pc test-project]$ pytest -sv ./test_code.py
=================================================================== test session starts ====================================================================
[...]
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
> ???
E pydantic.error_wrappers.ValidationError: 4 validation errors for PydanticBaseModel
E someInt
E value is not a valid integer (type=type_error.integer)
E someStr
E str type expected (type=type_error.str)
E someTypeA
E value is not a valid dict (type=type_error.dict)
E someTypeA
E value is not a valid dict (type=type_error.dict)
pydantic/main.py:338: ValidationError
================================================================= short test summary info ==================================================================
FAILED test_code.py::SimulacaoComboTest::test_sometype_method - pydantic.error_wrappers.ValidationError: 2 validat...
==================================================================== 1 failed in 0.94s =====================================================================
谢谢!
我不熟悉 mockito
,但您看起来像是在滥用用于 monkey-patching 对象的 when
和 ANY()
,这意味着 测试 值,而不是赋值。
mockito walk-through 展示了如何使用 when
函数。当您需要模拟某些功能时,您可以使用它。
ANY
函数是一个匹配器:它用于匹配例如函数调用中的参数。
下面是这两个操作的示例:
如果你想让os.path.exists
一直returnTrue
,不管路径如何,你可以调用:
>>> when(os.path).exists(ANY).thenReturn(True)
>>> os.path.exists("/path/example")
True
>>> os.path.exists("/another/example")
True
在这里,参数列表中的ANY
匹配任何参数,所以os.path.exists
将returnTrue
不管如何我们称之为。
如果我们只想将它 return True
用于特定路径,我们会改为:
>>> when(os.path).exists(ANY).thenReturn(True)
>>> when(os.path).exists("/another/example").thenReturn(True)
>>> os.path.exists("/path/example")
False
>>> os.path.exists('/another/example')
True
对于您正在做的事情,您似乎不需要这些结构中的任何一个。如果你想测试“当我创建一个 PydanticBaseModel
时,对象 returned 与我在构造它时使用的值相同”,那么你可以写:
import unittest
from model import PydanticBaseModel, SomeTypeA, SomeTypeB
class SomeTypeTest(unittest.TestCase):
def test_sometype_method(self):
expectedTypeA = SomeTypeA()
expectedTypeB = SomeTypeB()
expected = {
"someInt": 0,
"someStr": "",
"someTypeA": expectedTypeA,
"someTypeB": expectedTypeB,
}
model = PydanticBaseModel(
someInt=0,
someStr="",
someTypeA=expectedTypeA,
someTypeB=expectedTypeB,
)
assert model.dict() == expected
好的,朋友们!
我发现了 3 种不同的方法来模拟 Pydantic (BaseModel) class 的实例化(构造)。
注意:我不知道这些是否是解决问题的最佳方法,甚至不知道它们是否正确。所以我请你评论!
方法 1(我认为最好的)
import unittest
from unittest import mock
class SomeTypeTest(unittest.TestCase):
@mock.patch("some.path.pydantic_class.PydanticBaseModel.__init__")
def test_sometype_method(self, pydantic_base_model):
pydantic_base_model.return_value = None
<SOME_PATCH_DEPENDENT_CODE>
[...]
方法 2
import unittest
from unittest.mock import patch
from some.path.pydantic_class import PydanticBaseModel
class SomeTypeTest(unittest.TestCase):
def test_sometype_method(self):
with patch.object(PydanticBaseModel, "__init__", return_value=None):
<SOME_PATCH_DEPENDENT_CODE>
[...]
方法 3
import unittest
from unittest.mock import patch
class SomeTypeTest(unittest.TestCase):
def test_sometype_method(self):
patcher = patch("some.path.pydantic_class.PydanticBaseModel.__init__", return_value=None)
patcher.start()
<SOME_PATCH_DEPENDENT_CODE>
patcher.stop()
[...]
PLUS: 我继续坚持 Mockito 方法...
when(PydanticBaseModel).thenReturn(None)
... 失败,因为“PydanticBaseModel”class 使用了 Pydantic(BaseModel),这似乎是某种东西Mockito 无法处理。
谢谢!
我正在进行单元测试(基本上使用 pytest/unittest/mockito),我需要模拟使用 Pydantic (BaseModel) 实现的 class 的实例化。显然,如果不传递有效的有效数据,就不可能在这些情况下模拟 class。我不能使用“ANY()”,因为会发生错误。有什么方法可以模拟这个 class 而不必使用有效数据作为参数吗?
注意:显然问题的发生是因为正在使用 Pydantic。
我已经在 Internet 上进行了大量研究,但没有成功...有什么想法吗?
下面是我在测试中使用的非常简单的代码...
pydantic_class.py - Pydantic(基础模型)Class
from pydantic import BaseModel
from some.path.sometypea import SomeTypeA
from some.path.sometypeb import SomeTypeB
class PydanticBaseModel(BaseModel):
someInt: int
someStr: str
someTypeA: SomeTypeA
someTypeB: SomeTypeB
code_to_test.py - 要测试的代码
from some.path.pydantic_class import PydanticBaseModel
class ClassToTest():
def test_method(self)
pydantic_base_model = PydanticBaseModel(
someInt=0,
someStr="value",
someTypeA=<SomeTypeAObj>,
someTypeB=<SomeTypeBObj>
)
[...]
test_code.py - 测试代码
import unittest
from mockito import ANY, when
class SomeTypeTest(unittest.TestCase):
def test_sometype_method(self):
when(PydanticBaseModel(
someInt=ANY(),
someStr=ANY(),
someTypeA=ANY(),
someTypeB=ANY()
)).thenReturn(None)
[...]
测试输出(简体)
(test-project) [username@username-pc test-project]$ pytest -sv ./test_code.py
=================================================================== test session starts ====================================================================
[...]
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
> ???
E pydantic.error_wrappers.ValidationError: 4 validation errors for PydanticBaseModel
E someInt
E value is not a valid integer (type=type_error.integer)
E someStr
E str type expected (type=type_error.str)
E someTypeA
E value is not a valid dict (type=type_error.dict)
E someTypeA
E value is not a valid dict (type=type_error.dict)
pydantic/main.py:338: ValidationError
================================================================= short test summary info ==================================================================
FAILED test_code.py::SimulacaoComboTest::test_sometype_method - pydantic.error_wrappers.ValidationError: 2 validat...
==================================================================== 1 failed in 0.94s =====================================================================
谢谢!
我不熟悉 mockito
,但您看起来像是在滥用用于 monkey-patching 对象的 when
和 ANY()
,这意味着 测试 值,而不是赋值。
mockito walk-through 展示了如何使用 when
函数。当您需要模拟某些功能时,您可以使用它。
ANY
函数是一个匹配器:它用于匹配例如函数调用中的参数。
下面是这两个操作的示例:
如果你想让os.path.exists
一直returnTrue
,不管路径如何,你可以调用:
>>> when(os.path).exists(ANY).thenReturn(True)
>>> os.path.exists("/path/example")
True
>>> os.path.exists("/another/example")
True
在这里,参数列表中的ANY
匹配任何参数,所以os.path.exists
将returnTrue
不管如何我们称之为。
如果我们只想将它 return True
用于特定路径,我们会改为:
>>> when(os.path).exists(ANY).thenReturn(True)
>>> when(os.path).exists("/another/example").thenReturn(True)
>>> os.path.exists("/path/example")
False
>>> os.path.exists('/another/example')
True
对于您正在做的事情,您似乎不需要这些结构中的任何一个。如果你想测试“当我创建一个 PydanticBaseModel
时,对象 returned 与我在构造它时使用的值相同”,那么你可以写:
import unittest
from model import PydanticBaseModel, SomeTypeA, SomeTypeB
class SomeTypeTest(unittest.TestCase):
def test_sometype_method(self):
expectedTypeA = SomeTypeA()
expectedTypeB = SomeTypeB()
expected = {
"someInt": 0,
"someStr": "",
"someTypeA": expectedTypeA,
"someTypeB": expectedTypeB,
}
model = PydanticBaseModel(
someInt=0,
someStr="",
someTypeA=expectedTypeA,
someTypeB=expectedTypeB,
)
assert model.dict() == expected
好的,朋友们!
我发现了 3 种不同的方法来模拟 Pydantic (BaseModel) class 的实例化(构造)。
注意:我不知道这些是否是解决问题的最佳方法,甚至不知道它们是否正确。所以我请你评论!
方法 1(我认为最好的)
import unittest
from unittest import mock
class SomeTypeTest(unittest.TestCase):
@mock.patch("some.path.pydantic_class.PydanticBaseModel.__init__")
def test_sometype_method(self, pydantic_base_model):
pydantic_base_model.return_value = None
<SOME_PATCH_DEPENDENT_CODE>
[...]
方法 2
import unittest
from unittest.mock import patch
from some.path.pydantic_class import PydanticBaseModel
class SomeTypeTest(unittest.TestCase):
def test_sometype_method(self):
with patch.object(PydanticBaseModel, "__init__", return_value=None):
<SOME_PATCH_DEPENDENT_CODE>
[...]
方法 3
import unittest
from unittest.mock import patch
class SomeTypeTest(unittest.TestCase):
def test_sometype_method(self):
patcher = patch("some.path.pydantic_class.PydanticBaseModel.__init__", return_value=None)
patcher.start()
<SOME_PATCH_DEPENDENT_CODE>
patcher.stop()
[...]
PLUS: 我继续坚持 Mockito 方法...
when(PydanticBaseModel).thenReturn(None)
... 失败,因为“PydanticBaseModel”class 使用了 Pydantic(BaseModel),这似乎是某种东西Mockito 无法处理。
谢谢!