今天復(fù)習(xí)了MIT計(jì)算機(jī)導(dǎo)論的lecture7戳杀,關(guān)于測試和調(diào)試的概念有了一些基本了解,記錄下來怕忘記信卡。
測試基礎(chǔ)
The most important thing to say about testing is that its purpose is to show that bugs exist, not to show that a program is bug-free.
The key to testing is finding a collection of inputs, called a test suite, that has a high likelihood of revealing bugs, yet does not take too long to run.
Test suites based on exploring paths through the code called glass-box testing. based on exploring paths through the specification(說明書) called black-box testing.in black-box testing, we must consider two kinds of conditions
- typical conditions through the specification
- boundary conditions
- in glass-box testing, the test suite is path-conmplete, there are a few rules of thumb thatare usually worth following:
2.1 Exercise both branches of all if statements.
2.2 Make sure that each except clause is executed.
For each for loop, have test cases in which
2.3 The loop is not entered (e.g., if the loop is iterating over theelements of a list, make sure that it is tested on the empty list)
2.4 The body of the loop is executed exactly once, and
The body of the loop is executed more than once.
2.5 For each while loop,
- Look at the same kinds of cases as when dealing with for loops,and
- Include test cases corresponding to all possible ways of exiting the loop. For example, for a loop starting with
while len(L) > 0 and not L[i] == efind cases where the loop exits because len(L) is greater than
zero and cases where it exits because L[i] == e.
2.6 For recursive functions, include test cases that cause the function toreturn with no recursive calls, exactly one recursive call, and more thanone recursive call.
測試過程
- 單元測試(unit test)
- 集成測試(integration test)
- 反復(fù)上述過程多次
一個(gè)有用的方法是建立一段測試驅(qū)動(dòng)(test driver),即一段用來測試的代碼
調(diào)試
我們可以把調(diào)試看作一個(gè)檢索問題傍菇,如果某段代碼錯(cuò)誤,我們需要找出一個(gè)解釋丢习,到底是哪個(gè)部分造成代碼產(chǎn)生了不符合我們預(yù)期的結(jié)果,我們通常使用二分檢索和打印語句來完成這一過程咐低。
具體步驟是,如果某段代碼錯(cuò)誤见擦,我們?cè)谶@段代碼的中間位置放一個(gè)打印語句,若是打印語句不符合預(yù)期损痰,那我們知道這段代碼在打印語句之前就產(chǎn)生了錯(cuò)誤,那我們就關(guān)注打印語句之前的那一部分卢未,在這部分的中間放一個(gè)打印語句堰汉,運(yùn)行觀察代碼辽社,反之衡奥,則觀察打印語句之后的部分爹袁,如此循環(huán)往復(fù)矮固,直到調(diào)試成功。
一個(gè)常犯卻不易被發(fā)現(xiàn)的錯(cuò)誤--aliasing bug
如下列代碼
def isPal(x):
assert type(x) == list
temp = x
temp.reverse
if temp == x:
return True
else:
return False
def silly(n):
result = []
for i in range(n):
elem = raw_input('Enter element: ')
result.append(elem)
if isPal(result):
print('Yes')
else:
print('No')
在這段代碼中盹兢,有兩個(gè)錯(cuò)誤,當(dāng)我們要調(diào)用一個(gè)列表的方法時(shí)绎秒,形式應(yīng)該是a.reverse(), 若沒有(),我們只會(huì)得到reverse這個(gè)函數(shù)见芹,不能使列表轉(zhuǎn)向剂娄。還有一個(gè)錯(cuò)誤就是當(dāng)我們執(zhí)行到 if isPal(result) 語句時(shí)玄呛,我們假設(shè)result = [1, 2, 3], result 這個(gè)變量指向列表對(duì)象[1, 2, 3],當(dāng)后來執(zhí)行到 temp = x(temp = result)時(shí)徘铝,temp同樣指向列表對(duì)象[1, 2, 3],當(dāng)一個(gè)對(duì)象有多個(gè)引用的時(shí)候怕午,并且引用有不同的名稱,我們稱這個(gè)對(duì)象有別名(aliase)郁惜,因此當(dāng)temp被轉(zhuǎn)向時(shí),x同樣被轉(zhuǎn)向扳炬,因?yàn)樗麄儍蓚€(gè)指向同一個(gè)對(duì)象,這種情況很容易發(fā)生別名錯(cuò)誤恨樟,不過只發(fā)生在可變對(duì)象疚俱。改好的代碼如下
def isPal(x):
assert type(x) == list
temp = x[:]
temp.reverse.()
if temp == x:
return True
else:
return False
def silly(n):
result = []
for i in range(n):
elem = raw_input('Enter element: ')
result.append(elem)
if isPal(result):
print('Yes')
else:
print('No')