One of the benefits of continuous testing is that it makes a lot of other techniques more valuable. One great example of this is an inline assertion. Inline assertions are added to production code, rather than test code, to prove whether or not various conditions are exercised in the code. For example, let say we're working on a authorization system, and we have a class called User.
public class User
{
public final String name, password;
public User(String name, String password)
{
this.name = name;
this.password = password;
}
}
Suppose we're curious about whether or not we ever test the system with a user that has a null password. If we're working with a legacy system, we might wonder if this class is tested at all. When using a continuous test runner, we can quickly add an inline assertion to find out, like so:
public class User
{
public final String name, password;
public User(String name, String password)
{
org.junit.Assert.fail();
this.name = name;
this.password = password;
}
}
After inserting this inline assertion, the CT runner will run our tests and, if any failures occur, we'll know exactly which tests are exercising this constructor. If we want to dig deeper, we can change our inline assertion to:
org.junit.Assert.assertNotNull(password);
If this fails, we know that the condition we're interested in (namely, a user with a null password) is, in fact, created as part of our tests. We can check check the failing tests to determine how this case is supposed to be handled.
Inline assertions are intended to be temporary, and we remove them as soon as the tests finish running and we learn what we need to know. So, if we want to be able to add these assertions quickly, we can create Eclipse code templates to insert them with just a few keystrokes:
Download CT-Template-ProveNull
Try using this technique the next time you're working in an untested or partially tested project. It's a great way to identify untested cases in your code.
Nice point of view! I've never thought about assertion as an way to help debug and etc.
Thanks
Posted by: Daniel Fireman | 09/11/2009 at 04:28 AM
Interesting idea. I usually used java 'assert' for the same purpose (for example: assert false).
Using junit is interesting but I think your pattern might be difficult to implement in other IDEs. In IDEA, 'test' dependencies (like jUnit) are not visible for production code (like your User). (unless I'm wrong ;)
Posted by: Szczepan Faber | 09/21/2009 at 08:48 AM
If I'm understanding correctly, I'd put the junit jar in my eclipse build-path, but not in the compile phase of my maven config. That way, the "temporary" inline assertion would break the build if it became non-temporary. Am I understanding the usage pattern correctly?
Posted by: Ray | 09/23/2009 at 11:02 AM
Ray -- Yep. You can also add it to your maven config as a "test" scope dependency, use the maven eclipse plugin to generate your project, and get the same effect.
Posted by: Ben Rady | 09/23/2009 at 10:15 PM
Wouldn't it be simpler (especially for large projects) to have Cobertura (http://cobertura.sourceforge.net/) run over it? Or well, to check which methods are called by unit tests in any case - it can't figure out which tests call it with a null password parameter. But still.
Posted by: Cthulhu | 11/19/2009 at 06:03 AM
Right, the idea here is that coverage doesnt tell you the whole story. Inline assertions can help you detect cases in your code that are not tested, even if the code is 100% covered.
Posted by: Ben Rady | 11/19/2009 at 07:51 AM
Seems to me you are just relocating your 'test' i.e. to your production code.
Assuming you aren't practising TDD, I feel this approach requires the same 'brain-storming' (i.e. hindsight, foresight, whatever) to think up the cases.
And so I still think 'assert' is better as it can be switched off (removed) by the compiler.
BR
Posted by: Darren | 12/01/2009 at 05:29 AM
Darren, a critical difference between this technique and using the built in Java assertions is that these assertions are meant to be temporary. You add them, run your tests (or have Infinitest run them for you) and remove them as soon as you see the results. Theyre only in your code for a few seconds.
Posted by: Ben Rady | 12/01/2009 at 08:14 AM