Python unittest:如何指定自定义等式谓词?

时间:2017-02-23 18:20:36

标签: python unit-testing python-unittest

这可能是一个简单的问题;我想在Python unittest测试用例中使用自定义相等运算符。例如,假设我想测试一个"数字到字符串"函数,我想执行不区分大小写的字符串比较。

以下是我想写的内容:

class MyTest(unittest.TestCase):
    def testFoo(self):
        self.assertCheck(ci_string_eq,i2s(24),"Twenty-Four")

问题是assertCheck不是一件事。

一些明显的解决方法:

  • 使用assertTrue;问题是,测试用例失败变得不透明 没有用; "预期为真,得假,#34; Bleah。
  • 深入了解unittest并自行扩展;好吧,我希望避免这种情况:)

我希望我错过了一些明显的东西?

非常感谢提前!

编辑:有人建议我覆盖__eq__。这不是我想要的。具体来说,我的代码的客户端使用__eq__方法来确定 是否应该考虑两个对象"相同" (参见"伸展平等")。 但是,出于测试目的,我想使用不同的谓词进行测试。 所以重写__eq__并不能解决我的问题。

4 个答案:

答案 0 :(得分:2)

内置的unittest模块对此具有一种特定的方法,称为addTypeEqualityFunc。您可以阅读有关here的信息。 您只需要编写相等函数并传递它,然后像往常一样简单地使用assertEqual方法即可。

答案 1 :(得分:1)

Here's the full list of supported assertions in Python 3.6's unittest module.

正如您所看到的,没有断言需要自定义谓词来评估,但是您可以通过{{>自定义错误消息将{em>自定义错误消息传递给您的断言方法,从而获得更有用的错误消息1}}论证。

例如:

msg

如果这对你来说还不够,你真的不需要四处寻找class MyTest(unittest.TestCase): def testFoo(self): self.assertEqual(i2s(24),"Twenty-Four",msg="i2s(24) should be 'Twenty-Four'") :你可以用你需要的方法定义一个扩展unittest的TestCase的类,即:

unittest

然后您将测试定义为:

class CustomTestCase(unittest.TestCase):
  def assertCheck(self):
    ...

答案 2 :(得分:1)

好消息是,没有任何复杂的布线可以使用您自己的规则进行自定义断言。只需进行比较,收集任何有用的信息,然后根据需要调用fail(msg)。这将照顾您需要的任何报告。

当然,我很懒,我甚至不想收集有用的信息。我经常发现有用的是从预期数据和实际数据中删除不相关的东西,然后使用常规Route::post('/status/{statusId}/reply', [ 'uses' => '\CommendMe\Http\Controllers\StatusController@postReply', 'as' => 'status.reply', 'middleware' => ['auth'], ]);

以下是两种技术的示例,以及使用longMessage包含上下文的奖励:

$( ".replyForm" ).submit(function( e ) {

e.preventDefault();

var $token = $('input[name=_token]').val();
var dataString = $(this).serialize();
var $replyValue = $(this).attr('data-value');

$.ajax({
    type: "POST",
    url: host + '/status/' + $replyValue + '/reply',
    data: {replyValue: $replyValue, _token:$token},
    success: function(res) {

    }
 });
}); 

生成以下输出,包括上下文和通过和失败计数的报告。

assertEquals(expected, actual)

如果自定义比较适用于特定的类,那么您可以为该类add a custom equality operator。如果您在# file scratch.py from unittest import TestCase import sys def convert(i): results = 'ONE TOO THREE'.split() return results[i-1] class FooTest(TestCase): def assertResultEqual(self, expected, actual): expected_lower = expected.lower() actual_lower = actual.lower() if expected_lower != actual_lower: self.fail('Results did not match: {!r}, {!r}, comparing {!r}, {!r}'.format( expected, actual, expected_lower, actual_lower)) def assertLazyResultEqual(self, expected, actual): self.assertEqual(expected.lower(), actual.lower()) def assertLongLazyResultEqual(self, expected, actual): self.longMessage = True self.assertEqual(expected.lower(), actual.lower(), 'originals: {!r}, {!r}'.format(expected, actual)) def test_good_convert(self): expected = 'One' s = convert(1) self.assertResultEqual(expected, s) self.assertLazyResultEqual(expected, s) self.assertLongLazyResultEqual(expected, s) def test_bad_convert(self): expected = 'Two' s = convert(2) self.assertResultEqual(expected, s) def test_lazy_bad_convert(self): expected = 'Two' s = convert(2) self.assertLazyResultEqual(expected, s) def test_long_lazy_bad_convert(self): expected = 'Two' s = convert(2) self.assertLongLazyResultEqual(expected, s) 方法中执行此操作,则所有测试方法都可以使用该类调用$ python -m unittest scratch F.FF ====================================================================== FAIL: test_bad_convert (scratch.FooTest) ---------------------------------------------------------------------- Traceback (most recent call last): File "/home/don/workspace/scratch/scratch.py", line 43, in test_bad_convert self.assertResultEqual(expected, s) File "/home/don/workspace/scratch/scratch.py", line 18, in assertResultEqual actual_lower)) AssertionError: Results did not match: 'Two', 'TOO', comparing 'two', 'too' ====================================================================== FAIL: test_lazy_bad_convert (scratch.FooTest) ---------------------------------------------------------------------- Traceback (most recent call last): File "/home/don/workspace/scratch/scratch.py", line 50, in test_lazy_bad_convert self.assertLazyResultEqual(expected, s) File "/home/don/workspace/scratch/scratch.py", line 21, in assertLazyResultEqual self.assertEqual(expected.lower(), actual.lower()) AssertionError: 'two' != 'too' - two ? ^ + too ? ^ ====================================================================== FAIL: test_long_lazy_bad_convert (scratch.FooTest) ---------------------------------------------------------------------- Traceback (most recent call last): File "/home/don/workspace/scratch/scratch.py", line 57, in test_long_lazy_bad_convert self.assertLongLazyResultEqual(expected, s) File "/home/don/workspace/scratch/scratch.py", line 27, in assertLongLazyResultEqual 'originals: {!r}, {!r}'.format(expected, actual)) AssertionError: 'two' != 'too' - two ? ^ + too ? ^ : originals: 'Two', 'TOO' ---------------------------------------------------------------------- Ran 4 tests in 0.002s FAILED (failures=3) ,并且将调用您的自定义比较。

答案 3 :(得分:0)

您可以覆盖返回值类的__eq__方法,而无需通过子类化对原始单元进行卷积。

class Helper(FooReturnValueClass):

  def __init__(self, obj=None, **kwargs):
     self.obj = obj
     # any other attrs
     # probably good idea to skip calling super

  def __eq__(self, other):
    # logic

class MyTest(unittest.TestCase):

    def testFoo(self):
      expect = self.Helper(...)
      actual = ClassUnderTest.foo(...)
      self.assertEqual(expect, foo) # Order is important