我想将单元测试应用于简单的数字回放代码

时间:2017-07-11 11:39:55

标签: python unit-testing

我最近开始使用Python进行编程。有人告诉我,我无法访问此代码的单元测试的本质。我试着通过聆听单元测试和Python单元测试的重要性来练习。

代码如下所示。

# UpDown.py

import random
import unittest

servicenumber = 0
exp = 0

## Game play screen
def start_screen():
    global servicenumber
    exe = """
==============================
1. Up/Down Game Start
2. Exp check
3. exit
==============================
Please enter your desired service number."""

    print(exe)
    servicenumber = input()
    if servicenumber == 1:
        start_game()
    elif servicenumber == 2:
        check_exp()
    elif servicenumber == 3:
        game_exit()
    else:
        print "Please enter one of 1, 2, or 3."


## Up/Down This is the part of the game.
def start_game():
        re = 1
        global servicenumber
        global exp
        if servicenumber == 1:
            while re != 0:
                notice = """
    ==============================
    Randomly generated values ​​are from 1 to 100.
    Players should enter a number between 1 and 100.
    If you win, you gain 2 exp, and if you lose, it decreases by 1.
    Please enter 0 to finish.
    ==============================\n"""
                print(notice)
                var = input('input : ')
                if var > 100:
                    print 'Please enter a value between 1 and 100.'
                    continue
                elif var < 0:
                    print 'Please enter a value between 1 and 100.'
                    continue
                elif var == 0:
                    re = 0
                else:
                    print ''

                randvalue = random.randrange(1,101)
                if var > randvalue:
                    print 'Up'
                    exp = exp + 2
                    print "exp+2"
                    print "Your experience ",exp
                    print "Randomly generated values ",randvalue
                    continue
                elif var < randvalue:
                    print 'Down'
                    exp = exp-1
                    print 'Decreasing story ~~'
                    continue
                elif var == randvalue:
                    print 'The story of being tapped ~~'
                    continue
                else:
                    print "Randomly generated values ",randvalue
                    continue
        start_screen()


def check_exp():
    global servicenumber
    if servicenumber == 2:
        print "Experience: ",exp
        start_screen()


## (exit)
def game_exit():
    global servicenumber
    if servicenumber == 3:
        print 'Exit'
        exit()


if __name__ == "__main__":
    start_screen()
else:
    print "Imported. Start unit testing.\n"

我尝试练习的代码 我认为这是毫无意义的。

import unittest
import UpDownGame

class testing(unittest.TestCase):
    def test_start(self):
        self.assertTrue(UpDownGame.start_screen)

    def test_game(self):
        self.assertTrue(UpDownGame.start_game)

    def test_chkexp(self):
        self.assertTrue(UpDownGame.check_exp)

    def test_exit(self):
        self.assertTrue(UpDownGame.game_exit)


def initialize():
    return testing


if __name__ == "__main__":
    testsuite = (unittest.makeSuite(testing))
    unittest.TextTestRunner(verbosity=2).run(testsuite)

所以我想要关于单元测试的建议。 如果您让我知道如何将单元测试应用于此代码,我将非常感激。 另外,如果您认为我拥有自己需要的基本知识,请告诉我。

谢谢。

1 个答案:

答案 0 :(得分:0)

问题在于,当您编写代码时,您正在尝试编写测试,并且您已经开始使用本身难以测试的代码。如果你在测试的每个代码部分之前编写测试,那么你会以完全不同的方式编写代码。

因此,完全忽略您的代码,您需要一个'start_screen'函数,它将打印提示,读取一些输入,并根据该输入调用函数。您不希望硬连接被调用的函数(因为这会使测试更加困难),因此您可能会更改函数,因此它需要一个操作字典,然后您可以传递测试操作来代替真正的代码将运行。您也不希望它从input()读取,所以您可以再次进行自定义。使用print编写输出对于测试也是一个坏主意,因为如果你需要对它进行任何断言,你会想要捕获输出,但我们现在将忽略它。

所以,将def start_screen()更改为:

DEFAULT_ACTIONS = { 1: start_game, 2: check_exp, 3: game_exit }
def start_screen(actions=DEFAULT_ACTIONS, input=input):
    pass

并写一个测试:

def test_start_input_1_calls_action_1(self):
    calls = []
    dummy_actions = { 1: lambda: calls.append('action1') }
    def dummy_input():
        calls.append('input')
        return 1
    start_screen(actions=dummy_actions, input=dummy_input)
    assert calls == ['input', 'action1']

接下来验证测试是否编译并运行并因断言错误而失败。如果由于任何其他原因导致测试无法解决问题。

只有这样,您才更改start_screen,以便现在通过测试。

然后你可以添加其他测试。一个好的下一个测试是'input'函数在第一次调用时返回4,然后是1:

def test_start_input_4_prompts_again(self):
    calls = []
    inputs = [1, 4]
    dummy_actions = { 1: lambda: calls.append('action1') }
    def dummy_input():
        calls.append('input')
        return inputs.pop(0)
    start_screen(actions=dummy_actions, input=dummy_input)
    assert calls == ['input', 'input', 'action1']

现在验证是否收到断言错误,然后修改代码以便测试通过。现在最重要的一步是:你看两个测试并看到它们几乎相同,所以你将复制删除到另一个函数并修改测试,使它们看起来像这样:

def test_start_input_1_calls_action_1(self):
   self.start_helper([1], ['input', 'action1'])

def test_start_input_4_prompts_again(self):
   self.start_helper([4, 1], ['input', 'input', 'action1'])

def start_helper(self, inputs, expected_calls):
    ... add code here ...

然后继续为其他功能编写测试。您将希望丢失全局变量:已测试的函数需要干净且不依赖于外部设置的变量。此外,递归调用它可能是错误的事情,你可能想要考虑让start_screen有一个循环,在这种情况下,我们刚刚编写的测试必须为此更新。

在每个步骤中,您已经编写测试的事实将影响您对代码的看法。