Full statement coverage may be necessary for good testing coverage, but it isn't sufficient. Two places where statement coverage will be inadequate are branches and loops. In this episode, we'll look at branches, and specifically the differences between statement coverage and branch coverage.
Let's consider a case where branch coverage and statement coverage aren't the same. Suppose we test the following snippet. We can get complete statement coverage with a single test by using a berserk EvilOverLord:
bool DeathRay::ShouldFire(EvilOverLord& o, Target& t) {
double accumulated_rage = 0.0;
if (o.IsBerserk())
accumulated_rage += kEvilOverlordBerserkRage;
accumulated_rage += o.RageFeltTowards(t);
return (accumulated_rage > kDeathRayRageThreshold);
}
But what if DeathRay should fire at this Target even with a non-berserk Overlord? Well, we need another test for that. What should the test be? Let's rewrite the code a little bit. We would never see code like this in the real world, but it'll help us clarify an important point.
bool DeathRay::ShouldFire(EvilOverLord& o, Target& t) {
double accumulated_rage = 0.0;
if (o.IsBerserk()) {
accumulated_rage += kEvilOverlordBerserkRage;
} else {
}
accumulated_rage += o.RageFeltTowards(t);
return (accumulated_rage > kDeathRayRageThreshold);
}
Why do we add an else clause if it doesn't actually do anything? If you were to draw a flowchart of both snippets (left as an exercise – and we recommend against using the paper provided), the flowcharts would be identical. The fact that the else isn't there in the first snippet is simply a convenience for us as coders – we generally don't want to write code to do nothing special – but the branch still exists... put another way, every if has an else. Some of them just happen to be invisible.
When you're testing, then, it isn't enough to cover all the statements – you should cover all the the edges in the control flow graph – which can be even more complicated with loops and nested ifs. In fact, part of the art of large-scale white-box testing is finding the minimum number of tests to cover the maximum number of paths. So the lesson here is, just because you can't see a branch doesn't mean it isn't there – or that you shouldn't test it.
Remember to download this episode of Testing on the Toilet and post it in your office.
Permalink | Links to this post |
4 comments:
Hey Dave,
Your urinating friends might be interested in a handy tool for measuring coverage. In Java land Emma, Corbutura and Clover are by far the most common coverage tools.
Clover is the only tool that gives you per test coverage. That is, it tells you which test hit which class/method/statement/conditional. So you can see that the right test covered your if, rather than just any test. Check out the covererage report for Google-Guice.
Apologies for the blatant plug boys. now focus on your aim.
Cheers,
Pete.
Check out mutation testing, it's a technique for testing the quality of your test suite. The principle is simple:
a) in the current state, all tests pass
b) make an arbitrary modification to the code under test that breaks functionality
c) if your tests still pass, they are lacking
希望大家都會非常非常幸福~
「朵朵小語‧優美的眷戀在這個世界上,最重要的一件事,就是好好愛自己。好好愛自己,你的眼睛才能看見天空的美麗,耳朵才能聽見山水的清音。好好愛自己,你才能體會所有美好的東西,所有的文字與音符才能像清泉一樣注入你的心靈。好好愛自己,你才有愛人的能力,也才有讓別人愛上你的魅力。而愛自己的第一步,就是切斷讓自己覺得黏膩的過去,以無沾無滯的輕快心情,大步走向前去。愛自己的第二步,則是隨時保持孩子般的好奇,願意接受未知的指引;也隨時可以拋卻不再需要的行囊,一路雲淡風輕。親愛的,你是天地之間獨一無二的旅人,在陽光與月光的交替之中瀟灑獨行.............................................................................................................有時,你覺得痛。胃痛的時候,接受它,承認這個疼痛是你的身體的一部份,與它和平共處。心痛的時候,接受它,承認這個經驗是你的生命的一部份,與它和平共處。抗拒痛的存在,只會讓它更要證明它的存在,於是你就更痛。所以,.無論你有多麼不喜歡痛的感覺,還是要接納這個痛的事實。與你的痛站在同一邊,不逃避,不閃躲,不再與你的痛爭執,如此,你的痛才會漸漸不再胡鬧,才會乖乖平息下去。.................心願-你許下了一個心願,你閉上眼睛,在冥想之中把這個心願交託宙給宇整個讓宇宙推動它全部的力.量去執行.,你看見星球與星球的引力牽繫著彼此,你聽見虛空與虛空.唱裡著和妙美的聲音,為了你的心願,整個宇宙正在相互傳遞,然後你放下了心願,不僅是放下,最好你還把你的心願忘記,唯有如此,它才能脫離你,發展它自己,
當它在宇宙的遊歷結束之後,它自然會來到你身邊,以你曾經希望的方式回應你,許下,只是讓它發生,放下,才是讓>它實現,你的心願使你懂得不能執著的奧秘...................
Post a Comment