我最近开始使用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)
所以我想要关于单元测试的建议。 如果您让我知道如何将单元测试应用于此代码,我将非常感激。 另外,如果您认为我拥有自己需要的基本知识,请告诉我。
谢谢。
答案 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
有一个循环,在这种情况下,我们刚刚编写的测试必须为此更新。
在每个步骤中,您已经编写测试的事实将影响您对代码的看法。