【问题标题】:How to test class method that takes input?如何测试接受输入的类方法?
【发布时间】:2018-12-05 01:57:42
【问题描述】:

所以我有一个类方法,通过用户输入请求组大小;

def set_group_size(self):
    valid_input = False
    while not valid_input:
        response = input('Group Size: ')
        if isinstance(response, int):
            self.group_size = response
            valid_input = True

但是正在苦苦寻找最好的测试方法吗?我本质上是想确保 self.group_size 的值是一个整数,也是输入用户函数的整数。

我看到模拟在我一直在寻找的东西中非常受欢迎,所以这是我目前所拥有的,但它似乎并没有那么好,因为我可以更改方法本身和测试中的一些逻辑还是通过了;

def test_it_chooses_group_size(self):
    self.together.set_group_size = MagicMock(return_value=6)
    assert self.together.set_group_size() == 6
    assert type(self.together.set_group_size()) == int

我似乎很难理解测试一种接受用户输入并将其设置为类属性值的方法的概念。

【问题讨论】:

  • 不要在 Python 2 中使用 input,正如您的代码所暗示的那样。 (Python 3 的input always 返回一个str,而Python 2 的input 等价于eval(raw_input()),所以谁知道input 可能会返回什么,甚至做 i>.
  • 我正在使用 Python3。我应该始终使用raw_input()?
  • 如果您使用的是 Python 3,那么isinstance(response, int)永远为真。
  • @chepner,明白了。我发现这是一个问题,并在下面回答了我自己的问题。再次感谢!

标签: python unit-testing automated-tests pytest


【解决方案1】:

看起来我的方法本身还有一些其他问题(输入是一个字符串,所以从未满足条件),但我最终让它按我的预期工作;

def set_group_size(self):
    valid_input = False
    while not valid_input:
        r = input('Group Size: ')
        if r.isdigit():
            self.group_size = int(r)
            valid_input = True
        else:
            print('Please enter a valid number')

测试:

def test_it_chooses_group_size(self):
    with mock.patch('builtins.input', return_value='6'):
        self.together.set_group_size()
        assert self.together.group_size == 6
        assert type(self.together.group_size) == int

【讨论】:

    【解决方案2】:

    修改代码以使其更具可测试性(只需尝试response 变为int,而不是测试int(response) 是否会成功)。

    def set_group_size(self, input=input):
        while True:
            response = input('Group Size: ')
            try:
                self.group_size = int(response)
                break
            except ValueError:
                pass  # Try again
    

    要进行测试,请传递一个不从标准输入读取,而是从某个预定义数据源读取的函数。

    def make_input(stream):
        def _(prompt):
            return next(stream).rstrip("\n")
        return _
    
    def test_it_chooses_group_size(self):
        my_input = make_input(stringio.StringIO("foo\nbar\n3")
        self.together.set_group_size(my_input)
        assert self.together.group_size == 3
    
    def test_no_int_received(self):
        my_bad_input = make_input(stringio.StringIO("foo\n")
        old_group_size = self.together.group_size
        try:
            self.together.set_group_size(my_bad_input)
        except StopIteration:
            assert True  # Expected outcome, since input contains no int
        else:
            # This shouldn't be reachable; set_group_size has to
            # either terminate upon seeing an `int`, run forever, or raise
            # an uncaught StopIteration exception.
            assert False
    

    唯一没有测试的是set_group_size 是否会给你无限的机会输入一个整数,但无论如何这不是一个可测试的属性。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-05-04
      • 2014-05-10
      • 1970-01-01
      • 2015-01-08
      • 1970-01-01
      • 2012-05-22
      • 1970-01-01
      相关资源
      最近更新 更多