我似乎无法理解Python中的嘲笑。我有一个全球功能:
a.py:
def has_permission(args):
ret_val = ...get-true-or-false...
return ret_val
b.py:
class MySerializer(HyperlinkedModelSerializer):
def get_fields():
fields = super().get_fields()
for f in :
if has_permission(...):
ret_val[f.name] = fields[f]
return ret_val
c.py:
class CountrySerializer(MySerializer):
class Meta:
model = Country
问题:现在我要测试c.py,但我想模拟a.py中定义的 has_permission 函数,但是在get_fields中调用 - 在b.py中定义的MySerializer类的方法...我该怎么做?
我尝试过这样的事情:
@patch('b.MySerializer.has_permission')
和
@patch('b.MySerializer.get_fields.has_permission')
和
@patch('a.has_permission')
但我尝试的所有内容都不起作用且has_permission仍然执行,或者python抱怨它无法找到属性'has_permission'
完成修补:
test.py
class TestSerializerFields(TestCase):
@patch(... the above examples....)
def test_my_country_serializer():
s = CountrySerializer()
self..assertTrue(issubclass(my_serializer_fields.MyCharField, type(s.get_fields()['field1'])))
答案 0 :(得分:8)
您需要修补add (T object)
模块中的全局:
b
因为那是您的代码所在的位置。
另请参阅@patch('b.has_permission')
文档的Where to patch section。
答案 1 :(得分:0)
您需要在测试运行时修补存在的方法。如果您尝试在测试代码已导入它之后修改定义它的方法,那么该修补程序将不起作用。在@patch(...)
执行时,测试中的测试代码已经将全局方法抓到了自己的模块中。
以下是一个例子:
app/util/config.py
# This is the global method we want to mock
def is_search_enabled():
return True
app/service/searcher.py
# Here is where that global method will be imported
# when this file is first imported
from app.util.config import is_search_enabled
class Searcher:
def __init__(self, api_service):
self._api_service = api_service
def search(self):
if not is_search_enabled():
return None
return self._api_service.perform_request('/search')
test/service/test_searcher.py
from unittest.mock import patch, Mock
# The next line will cause the imports of `searcher.py` to execute...
from app.service.searcher import Searcher
# At this point, searcher.py has imported is_search_enabled into its module.
# If you later try and patch the method at its definition
# (app.util.config.is_search_enabled), it will have no effect because
# searcher.py won't look there again.
class MockApiService:
pass
class TestSearcher:
# By the time this executes, `is_search_enabled` has already been
# imported into `app.service.searcher`. So that is where we must
# patch it.
@patch('app.service.searcher.is_search_enabled')
def test_no_search_when_disabled(self, mock_is_search_enabled):
mock_is_search_enabled.return_value = False
mock_api_service = MockApiService()
mock_api_service.perform_request = Mock()
searcher = Searcher(mock_api_service)
results = searcher.search()
assert results is None
mock_api_service.perform_request.assert_not_called()
# (For completeness' sake, make sure the code actually works when search is enabled...)
def test_search(self):
mock_api_service = MockApiService()
mock_api_service.perform_request = mock_perform_request = Mock()
searcher = Searcher(mock_api_service)
expected_results = [1, 2, 3]
mock_perform_request.return_value = expected_results
actual_results = searcher.search()
assert actual_results == expected_results
mock_api_service.perform_request.assert_called_once_with('/search')