In the movie Amadeus, the Austrian Emperor criticizes Mozart's music as having “too many notes.” How many tests are “too many” to test one function?
Consider the method decide:
public void decide(int a, int b, int c, int d,
int e, int f) {
if (a > b || c > d || e > f) {
DoOneThing();
} else {
DoAnother();
} // One-letter variable names are used here only
because of limited space.
} // You should use better names. Do as I say, not
as I do. :-)
How many tests could we write? Exercising the full range of int values for each of the variables would require 2192 tests. We'd have googols of tests if we did this all the time! Too many tests.
What is the fewest number of tests we could write, and still get every line executed? This would achieve 100% line coverage, which is the criterion most code-coverage tools measure. Two tests. One where (a > b || c > d || e > f) is true; one where it is false. Not enough tests to detect most bugs or unintentional changes in the code.
How many tests to test the logical expression and its sub-expressions? If you write a test of decide where a == b, you might find that the sub-expression a > b was incorrect and the code should have been a >= b. And it might make sense to also run tests where a < b and a > b. So that's three tests for a compared to b. For all of the parameters, that would 3 * 3 * 3 = 27 tests. That's probably too many.
How many tests to test the logical expression and its sub-expressions independently? Consider another version of decide, where the logical sub-expressions have been extracted out:
public void decide(int a, int b, int c, int d,
int e, int f) {
if (tallerThan(a, b)
|| harderThan(c, d)
|| heavierThan(e, f)) {
DoOneThing();
} else {
DoAnother();
}
}
boolean tallerThan(int a, int b) { return a > b; }
// Note “package scope”
boolean harderThan(int c, int d) { return c > d; }
// rather than public; JUnit
boolean heavierThan(int e, int f) { return e > f; }
// tests can access these.
We can write four tests for decide. One where tallerThan is true. One where harderThan is true. One where heavierThan is true. And one where they are all false. We could test each of the extracted functions with two tests, so the total would be 4 + 2 * 3 = 10 tests. This would be just enough tests so that most unintentional changes will trigger a test failure. Exposing the internals this way trades decreased encapsulation for increased testability. Limit the exposure by controlling scope appropriately, as we did in the Java code above.
How many tests is too many? The answer is “It depends.” It depends on how much confidence the tests can provide in the face of changes made by others. Tests can detect whether a programmer changed some code in error, and can serve as examples and documentation. Don't write redundant tests, and don't write too few tests.
Remember to download this episode of Testing on the Toilet and post it in your office. Permalink | Links to this post |
10 comments:
Great example! A suggestion if I may?
The 27 test example doesn't take advantage of the independence provided by OR. One doesn't need to test every combination of pairs, as there is no conditional logic between them. Consider:
A = B, C = D, E = F : DoAnother()
A < B, C < D, E < F : DoAnother()
A > B, C < D, E < F : DoOneThing()
A < B, C > D, E < F : DoOneThing()
A < B, C < D, E > F : DoOneThing()
That's five tests, but it tests equivalence, greater than, and less than for each pair.
This provides the same confidence as the 27 test example, with half the tests of the decreased encapsulation example.
-Ben
And if one of the 'OR's changed to an 'XOR', the tests would still pass, but the behaviour would change.
Taking advantage of the logical independence of OR produces a gap due to its reliance on the use of OR.
Mind you whilst the level confidence may not be the same as with the 27 test example, the drop may not be particularly significant, thus illustrating the original point I suppose.
You mention, "Limit the exposure by controlling scope appropriately, as we did in the Java code above.".
I'm not a java guy but it appears to me that you've made the extracted functions private and not testable from outside this class.
What am I missing?
Gary, the first comment under the first extracted conditional indicates the visibility which is package.
Thanks Tim.
Just not paying close enough attention.
yes... the format of this blog isn't as code friendly as an 8.5x11 page. I've been playing with the code format. Small font, or break the lines... sometimes with resulting oddness. Comments on that appreciated.
It is also interesting to look at the NPath complexity metric for a function or method as it gives you a pretty good estimate of how many tests you need.
網頁設計,情趣用品店,情趣用品專賣網
A片,色情A片,免費A片,成人影片,色情影片,a片免費看,情色貼圖,情色文學,情色小說,色情小說
AV,AV女優
辣妹視訊,美女視訊,視訊交友網,視訊聊天室,視訊交友,視訊美女,免費視訊,免費視訊聊天,視訊交友90739,免費視訊聊天室,成人聊天室,視訊聊天,視訊交友aooyy
哈啦聊天室,辣妺視訊,A片,色情A片,視訊,080視訊聊天室,視訊美女34c,視訊情人高雄網,視訊交友高雄網,0204貼圖區,sex520免費影片,情色貼圖,視訊ukiss
希望大家都會非常非常幸福~
「朵朵小語‧優美的眷戀在這個世界上,最重要的一件事,就是好好愛自己。好好愛自己,你的眼睛才能看見天空的美麗,耳朵才能聽見山水的清音。好好愛自己,你才能體會所有美好的東西,所有的文字與音符才能像清泉一樣注入你的心靈。好好愛自己,你才有愛人的能力,也才有讓別人愛上你的魅力。而愛自己的第一步,就是切斷讓自己覺得黏膩的過去,以無沾無滯的輕快心情,大步走向前去。愛自己的第二步,則是隨時保持孩子般的好奇,願意接受未知的指引;也隨時可以拋卻不再需要的行囊,一路雲淡風輕。親愛的,你是天地之間獨一無二的旅人,在陽光與月光的交替之中瀟灑獨行.............................................................................................................有時,你覺得痛。胃痛的時候,接受它,承認這個疼痛是你的身體的一部份,與它和平共處。心痛的時候,接受它,承認這個經驗是你的生命的一部份,與它和平共處。抗拒痛的存在,只會讓它更要證明它的存在,於是你就更痛。所以,.無論你有多麼不喜歡痛的感覺,還是要接納這個痛的事實。與你的痛站在同一邊,不逃避,不閃躲,不再與你的痛爭執,如此,你的痛才會漸漸不再胡鬧,才會乖乖平息下去。.................心願-你許下了一個心願,你閉上眼睛,在冥想之中把這個心願交託宙給宇整個讓宇宙推動它全部的力.量去執行.,你看見星球與星球的引力牽繫著彼此,你聽見虛空與虛空.唱裡著和妙美的聲音,為了你的心願,整個宇宙正在相互傳遞,然後你放下了心願,不僅是放下,最好你還把你的心願忘記,唯有如此,它才能脫離你,發展它自己,
當它在宇宙的遊歷結束之後,它自然會來到你身邊,以你曾經希望的方式回應你,許下,只是讓它發生,放下,才是讓>它實現,你的心願使你懂得不能執著的奧秘...................
Good example of equivalence class partioning.
Post a Comment