【问题标题】:How to test a Function that takes no parameters如何测试不带参数的函数
【发布时间】:2020-10-03 17:39:16
【问题描述】:

我是新来的编程新手(我只编程了 2 周)。有没有人对如何测试不带参数的函数有任何建议。我已经测试了带参数的函数,但没有测试不带参数的函数。

在测试函数中,我尝试在 valid_letter() 函数中传递一个预期为字母“a”的参数。但它给出了'a'未定义的错误。

def valid_letter():
    '''Function valid_letter
       Parameters None
       continuously asks for a valid letter
       if invalid data is provided
    '''
    while True:
        column = input("What column do you wish to select from a to g? ")
        if column != "a" and column != "b" and\
           column != "c" and column != "d" and\
           column != "e" and column != "f" and\
           column != "g" and column != "h":
           print("Your input is invalid")
           continue
        else:
         return column
         break  

def check_valid_column(expect):
    answer = valid_letter()
    print("Input: {}".format(answer))
    print("Expected: {}, Actual {}".format(expect, answer))

def main():

   check_valid_column(a)
main()

【问题讨论】:

  • 欢迎来到 SO!你能给我们提供预期的输出吗?并可能澄清你想在这里做什么?
  • 我猜你打算做check_valid_column("a"),所以使用字符“a”,而不是变量a
  • 您可以将 if 子句重写为 if column not in ["a", "b", "c", "d", "e", "f", "g", "h"]:。此外,在return column 之后不需要break。在这种情况下不需要continue,因为它已经隐式发生了。
  • 看看这是否有帮助:stackoverflow.com/questions/6271947/…
  • @trincot 谢谢。这就是它不起作用的原因,我没有将字母作为字符串传递给它。

标签: python


【解决方案1】:

该函数将在没有参数的情况下工作,并且仍然与用户输入一样,因为您在调用的函数中有 input()。

【讨论】:

    【解决方案2】:

    (注意:原始函数由于缩进而损坏,所以在我修复它时,我冒昧地重写它以使其更简单。它的行为仍应与您预期的原始实现和测试策略完全相同,即无论实现细节如何,问题的真正重点都是完全相同的。)

    一种方法是使用patch

    def valid_letter() -> str:
        '''
        Prompts the user for a column between 'a' and 'g'.
        Continuously asks for a valid letter if invalid data is provided.
        '''
        while True:
            column = input("What column do you wish to select from a to g? ")
            if ord(column) in range(ord('a'), ord('g') + 1):
                return column
            print("Your input is invalid")
    
    
    from unittest.mock import Mock, patch
    
    
    def test_valid_letter() -> None:
        with patch('builtins.input', new=Mock(return_value='a')):
            assert valid_letter() == 'a'
        with patch('builtins.input', new=Mock(side_effect=['z', 'q', 'g', 'c'])):
            assert valid_letter() == 'g'
    
    
    test_valid_letter()
    

    测试中的patch 语句将内置input 函数替换为返回特定参数的Mock 对象。在第一个测试中,它只返回'a',因此我们断言valid_letter() 将返回相同的值。在第二个测试中,每次调用它都会从列表中返回连续的值;我们断言valid_letter() 将继续循环调用它,直到它到达'g'

    另一种方法是通过依赖注入:

    from typing import Callable
    from unittest.mock import Mock
    
    
    def valid_letter(input_func: Callable[[str], str]) -> str:
        '''
        Prompts the user for a column between 'a' and 'g', using input_func.
        Continuously asks for a valid letter if invalid data is provided.
        '''
        while True:
            column = input_func("What column do you wish to select from a to g? ")
            if ord(column) in range(ord('a'), ord('g') + 1):
                return column
            print("Your input is invalid")
    
    
    def test_valid_letter() -> None:
        assert valid_letter(Mock(return_value='a')) == 'a'
        assert valid_letter(Mock(side_effect=['z', 'q', 'g', 'c'])) == 'g'
    
    
    test_valid_letter()
    

    在这个例子中,不是让valid_letter 调用内置的input 函数,而是接受调用者提供的任意输入函数。如果你这样称呼它:

    valid_letter(input)
    

    那么它的行为与原来的完全一样,但调用者也可以传入任意替换,而不必使用patch。这使得测试更容易一些,并且它还允许调用者包装或替换 input 以允许不同的 UI 样式 - 例如,如果在 GUI 应用程序中使用此函数,则调用者可以传入input_func 通过对话框而不是终端提示用户。

    相同的测试/注入逻辑适用于 print 函数——您可能会发现让您的测试验证每次输入无效值时调用 print 很有用,并且另一个调用者可能会发现它对使用替代输出函数。

    【讨论】:

    • 这是一个新程序员。 IMO,在他的代码中添加类型信息是非常不合适的。那只会让他/她感到困惑。 - 你也在向他/她扔一个 lambda。这将超出 OP 的想象。我建议你在帮助那些直截了当地说自己是新程序员的人时,要坚持基础知识。
    • 就个人而言,当我学习时,我发现按照良好实践在“现实世界”中编写代码示例最有用;从长远来看,教坏习惯的玩具教室示例只会减慢您的速度,因此我避免为新程序员“简化”并专注于提供工作示例。如果他们想了解更多信息,现在他们可以用谷歌搜索一些东西,如果没有,他们可以复制+粘贴或丢弃他们不需要的部分。幸运的是,那里有各种各样的示例,因此每个人都可以找出最适合他们的方法!
    【解决方案3】:

    您拨打valid_letter() 的方式很好。这不是问题。但是您打算验证输入是“a”(显然代表正确答案)。

    那么你不应该做check_valid_column(a),因为a不是一个定义的变量,而是check_valid_column("a"),所以用字符“a”。

    【讨论】:

      猜你喜欢
      • 2016-06-21
      • 2018-09-20
      • 2013-06-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-01
      • 1970-01-01
      相关资源
      最近更新 更多