Python-不管消息是如何构造的,都要断言记录器输出的子字符串
例如,我发现了许多关于如何断言某个日志的示例 但是,我不知道如何将断言与消息的具体构造方式分离。测试只关心记录的特定ID 测试代码Python-不管消息是如何构造的,都要断言记录器输出的子字符串,python,unit-testing,logging,python-mock,Python,Unit Testing,Logging,Python Mock,例如,我发现了许多关于如何断言某个日志的示例 但是,我不知道如何将断言与消息的具体构造方式分离。测试只关心记录的特定ID 测试代码 mock_logger.warn.assert_called_with( all_match( contains_string('user-id'), contains_string('team-id') ) ) 应该对两者都有效 生产代码1(记录器汇编消息): 及 生产代码2(我们组装消息并包括异常): 这将
mock_logger.warn.assert_called_with(
all_match(
contains_string('user-id'),
contains_string('team-id')
)
)
应该对两者都有效
生产代码1(记录器汇编消息):
及
生产代码2(我们组装消息并包括异常):
这将无法正常工作,但我正在考虑捕获参数或设置自定义日志追加器,并对最终消息进行断言。
请忽略任何输入错误/潜在的语法错误,因为我没有在IDE中编写代码如果您希望
warn
方法接受多个参数并格式化字符串本身,我认为像all\u match
这样的匹配器不起作用。匹配器只匹配一个参数
您将all\u match
作为assert\u调用的
的第一个参数传递,因此它只能将第一个参数与mock\u logger.warn的调用相匹配。这就是为什么测试代码将通过生产代码2而不是生产代码1
在生产代码2中,warn
的第一个参数是字符串“无法处理团队id和用户id的订单”
。mock将其第一个参数传递给all\u match
,以便找到它要查找的内容
在生产代码1中,warn
的第一个参数是“无法处理团队%s和用户%s的订单”
。这就是你所知道的一切。第二个和第三个参数包含要查找的字符串all\u match
,但它无权访问这些字符串
手动检查对mock的调用对于这两种情况都有效,而不是将matcher传递给assert\u,并用调用\u。下面是我的意思的一个不雅但可读的实现:
mock_logger = unittest.Mock()
...
# Call production code
...
calls = mock_logger.warn.call_args_list # gets a list of calls made to the mock
first_call = calls[0] # each call object in call_args_list is a tuple containing 2 tuples: ((positional args), (keyword args)). Let's grab the first one.
arguments = first_call[0] # the positional arguments are the first tuple in the call
if len(arguments) == 1: # If warn got 1 argument, it's a string. Look for 'team-id' and 'user-id' in that argument
self.assertIn('team-id', arguments[0])
self.assertIn('user-id', arguments[0])
elif len(arguments) == 3: # if warn got 3 arguments, 'team-id' and 'user-id' should have been the 2nd and 3rd arguments.
self.assertEqual("Order for team %s and user %s could not be processed", arguments[0])
self.assertEqual('team-id', arguments[1])
self.assertEqual('user-id', arguments[2])
如果确实要使用匹配器,则必须始终将单个字符串传递给记录器。warn
,这意味着在调用warn
之前格式化字符串
logger.warn(
"Order for team {} and user {} could not be processed"
.format('team-id', 'user-id'),
ex
)
mock_logger = unittest.Mock()
...
# Call production code
...
calls = mock_logger.warn.call_args_list # gets a list of calls made to the mock
first_call = calls[0] # each call object in call_args_list is a tuple containing 2 tuples: ((positional args), (keyword args)). Let's grab the first one.
arguments = first_call[0] # the positional arguments are the first tuple in the call
if len(arguments) == 1: # If warn got 1 argument, it's a string. Look for 'team-id' and 'user-id' in that argument
self.assertIn('team-id', arguments[0])
self.assertIn('user-id', arguments[0])
elif len(arguments) == 3: # if warn got 3 arguments, 'team-id' and 'user-id' should have been the 2nd and 3rd arguments.
self.assertEqual("Order for team %s and user %s could not be processed", arguments[0])
self.assertEqual('team-id', arguments[1])
self.assertEqual('user-id', arguments[2])