如何测试需要输入的类方法?

时间:2018-12-05 01:57:42

标签: python unit-testing automated-tests pytest

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

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

我似乎在为测试一种接受用户输入并将其设置为类属性值的方法的概念而苦恼。

2 个答案:

答案 0 :(得分:0)

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

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

答案 1 :(得分:0)

修改代码以使其更具可测试性(只需通过 try 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是否会给您无限的机会输入整数,但这毕竟不是可测试的属性。