习题47:自动化测试
通过测试代码简化测试过程
被测试的代码
class Room(object):
def __init__(self, name, description):
self.name = name
self.description = description
self.paths = {}
def go(self, direction):
return self.paths.get(direction, None)
def add_paths(self, paths):
self.paths.update(paths)
测试代码
from nose.tools import *
from DataMining.BFF27_52 import Room
def test_room():
gold = Room("GoldRoom",
"""This room has gold in it you can grad.
There's a door to the north.
""") # 测试__init__那个函数,需要输入name和
assert_equal(gold.name, "GoldRoom")
assert_equal(gold.paths, {})
def test_room_paths():
center = Room("Center", "Test room in the center.")
north = Room("North", "Test room in the nroth.")
south = Room("South", "Test room in the south.")
center.add_paths({'north': north, 'south': south})
assert_equal(center.go('north'), north) # 走north就到了north
assert_equal(center.go('south'), south)
def test_map():
start = Room("Start", "You can go west and down a hole.")
west = Room("Trees", "There are trees here, you can go east.")
down = Room("Dungeon", "It's dark down here, you can go up.")
start.add_paths({'west': west, 'down': down})
west.add_paths({'east': start})
down.add_path({'up': start})
assert_equal(start.go('west'), west)
assert_equal(start.go('west').go('east'), start) # 回到原点
assert_equal(start.go('down').go('up'), start)
有个错,add_paths少写了一个s,加上之后(给的代码里每加)
其实吧,我并没怎么看懂这个测试代码,解释说创建一些小房间,测试基本的房间功能,然后测试了路径,最后测试了整个地图。
尤其assert_equal,书上说它保证了你设置的变量,以及在Room里设置的路径和你的期望相符。
常用于测试代码,用于判断两个值是否相等,不等抛出异常。
习题48:更复杂的用户输入
前面要求用户输入完全正确后才能执行,这里希望用户的输入和常用英语很接近也应该可以。所以建立相关模组实现。
作者在游戏里创建了下面这些语汇:
表示方向: north, south, east, west, down, up, left, right, back.
动词: go, stop, kill, eat.
修饰词: the, in, of, from, at, it
名词: door, bear, princess, cabinet.
数词: 由 0-9 构成的数字.
什么是异常?
异常是运行某个函数时得到的一个错误,函数在碰到错误时会提出一个异常。
处理异常的方法是使用try和except两个关键字
给出测试代码,自己写程序
from nose.tools import *
from DataMining.BFF27_52 import lexicon
def test_direction():
assert_equal(lexicon.scan("north"), [('direction', 'north')])
result = lexicon.scan("north south east")
assert_equal(result, [('direction', 'north'),
('direction', 'south'),
('direction', 'east')])
def test_verbs():
assert_equal(lexicon.scan("go"), [('verb', 'go')])
result = lexicon.scan("go kill eat")
assert_equal(result, [('verb', 'go'),
('verb', 'kill'),
('verb', 'eat')])
def test_stops():
assert_equal(lexicon.scan("the"), [('stop', 'the')])
result = lexicon.scan("the in of")
assert_equal(result, [('stop', 'the'),
('stop', 'in'),
('stop', 'of')])
def test_noun():
assert_equal(lexicon.scan("bear"), [('noun', 'bear')])
result = lexicon.scan("bear princess")
assert_equal(result, [('noun', 'bear'),
('noun', 'princess')])
def test_numbers():
assert_equal(lexicon.scan("1234"), [('number', 1234)])
result = lexicon.scan("3 91234")
assert_equal(result, [('number', 3),
('number', 91234)])
def test_errors():
assert_equal(lexicon.scan("ASDFAFASDF"), [('error', 'ASDFAFASDF')])
result = lexicon.scan("bear IAS princess")
assert_equal(result, [('noun', 'bear'),
('error', 'IAS'),
('noun', 'princess')])
被测试代码(参考笨方法学python Lesson 46 - 49 )
class Lexicon(object):
def scan(self, stuff):
self.stuff = stuff
words = stuff.split() # 对句子进行分割
sentence = []
for i in words:
try:
sentence.append(('number', int(i)))
except ValueError:
if i in ['north', 'south', 'east', 'west', 'down', 'up', 'left', 'right', 'back']:
sentence.append(('direction', i))
elif i in ['go', 'stop', 'kill', 'eat']:
sentence.append(('verb', i))
elif i in ['the', 'in', 'of', 'from', 'at', 'in']:
sentence.append(('stop', i))
elif i in ['door', 'bear', 'princess', 'cabinet']:
sentence.append(('noun', i))
else:
sentence.append(('error', i))
return sentence
lexicon = Lexicon()
虽然理解了,但是根据测试代码写出源代码还是有点困难。
习题49:创建句子
# 在上一习题的基础上
print(lexicon.scan("go north"))
print(lexicon.scan("kill the princess"))
print(lexicon.scan("eat the bear"))
print(lexicon.scan("open the door and smack the bear in the nose"))
匹配(Match)和窥视(Peek)
为了达到这个效果,你需要四样工具:
1. 循环访问元组列表的方法,这挺简单的。
2. 匹配我们的主谓宾设置中不同种类元组的方法。
3. 一个“窥视”潜在元组的方法,以便做决定时用到。
4. 跳过(skip)我们不在乎的内容的方法,例如形容词、冠词等没有用处的词汇。
被测试代码(书上给出的源代码)
class ParserError(Exception):
pass
class Sentence(object):
def __init__(self, subject, verb, object):
self.subject = subject[1]
self.verb = verb[1]
self.object = object[1]
def peek(word_list): # 查看元组列表中的下一个成员,做匹配以后再对它做下一步动作
if word_list:
word = word_list[0]
return word[0]
else:
return None
def match(word_list, expecting):
if word_list:
word = word_list.pop(0)
if word[0] == expecting:
return word
else:
return None
else:
return None
def skip(word_list, word_type):
while peek(word_list) == word_type:
match(word_list, word_type)
def parse_verb(word_list):
skip(word_list, 'stop')
if peek(word_list) == 'verb':
return match(word_list, 'verb')
else:
raise ParserError("Expected a verb next.")
def parse_object(word_list):
skip(word_list, 'stop')
nexta = peek(word_list)
if nexta == 'noun':
return match(word_list, 'noun')
if nexta == 'direction':
return match(word_list, 'direction')
else:
raise ParserError("expected a moun or direction next.")
def parse_subject(word_list, subj):
verb = parse_verb(word_list)
obj = parse_object(word_list)
return Sentence(subj, verb, obj)
def parse_sentence(word_list):
skip(word_list, 'stop')
start = peek(word_list)
if start == 'noun':
subj = match(word_list, 'noun')
return parse_subject(word_list, subj)
elif start == 'verb': # assume the subject is the player then
return parse_subject(word_list, ('noun', 'player'))
else:
raise ParserError("Must start with subject, object, or verb not: %s" % start)
测试代码
from nose.tools import *
from DataMining import BFF27_49
def test_peek():
words = [('noun', 'apple'), ('stop', 'the'), ('verb', 'kill')]
assert_equal(BFF27_49.peek(words), 'noun')
assert_equal(BFF27_49.peek([]), None)
def test_match():
assert_equal(BFF27_49.match([], 'noun'), None)
words = [('noun','apple'),('stop','the'), ('verb','kill')]
assert_equal(BFF27_49.match(words, 'noun'), ('noun', 'apple'))
assert_equal(BFF27_49.match(words, 'verb'), None)
# def test_skip():
def test_parse_verb():
words=[('stop', 'a'), ('stop', 'the'), ('verb', 'kill'), ('noun', 'apple')]
assert_equal(BFF27_49.parse_verb(words), ('verb', 'kill'))
words_error=[('stop', 'a'), ('stop', 'the'), ('noun', 'apple'), ('verb', 'kill')]
assert_raises(BFF27_49.ParserError, BFF27_49.parse_verb, words_error)
def test_parse_object():
words = [('noun', 'apple'), ('verb', 'kill')]
assert_equal(BFF27_49.parse_object(words), ('noun', 'apple'))
words2 = [('direction', 'east'), ('verb', 'kill')]
assert_equal(BFF27_49.parse_object(words2), ('direction', 'east'))
words_error = [('stop', 'a'), ('verb', 'run'), ('verb', 'kill')]
assert_raises(BFF27_49.ParserError, BFF27_49.parse_object, words_error)
def test_parse_sentence():
words = [('stop', 'a'), ('noun', 'apple'), ('verb', 'kill'), ('direction', 'east')]
result = BFF27_49.parse_sentence(words)
assert_equal(result.subject, 'apple')
assert_equal(result.verb, 'kill')
assert_equal(result.object, 'east')