Sunday, April 30, 2006
Simian
This is really a tool to deal with the problem that you should only code your program once. Just as with a database, only store your data in one place and don't duplicate the same approach should be taken to coding. This is the principle behind the 2nd normal form for a relational database.
I can think of one exception where Simian would give an incorrect result, and that is with code generation. Code generation is likely to produce lots of duplicate code, but it doesn't break the principle that you shouldn't duplicate code. The reason is that it is the compressed representation of the code, and the code generator itself that is important, not the output.
Well almost. If you do have lots of duplicate code, then you are going to have a larger program than necessary. Simian can help detect this, and you can then feed this back into your code generator, to optimise the output.
Friday, April 28, 2006
FxCop and Nunit
- JUnitStaticSuite: The suite() method in a JUnit test needs to be both public and static.
- JUnitSpelling: Some JUnit framework methods are easy to misspell.
- JUnitAssertionsShouldIncludeMessage: JUnit assertions should include a message - i.e., use the three argument version of assertEquals(), not the two argument version.
- JUnitTestsShouldIncludeAssert: JUnit tests should include at least one assertion. This makes the tests more robust, and using assert with messages provide the developer a clearer idea of what the test does.
- TestClassWithoutTestCases: Test classes end with the suffix Test. Having a non-test class with that name is not a good practice, since most people will assume it is a test case. Test classes have test methods named testXXX.
- UnnecessaryBooleanAssertion: A JUnit test assertion with a boolean literal is unnecessary since it always will eval to the same thing. Consider using flow control (in case of assertTrue(false) or similar) or simply removing statements like assertTrue(true) and assertFalse(false). If you just want a test to halt, use the fail method.
- UseAssertEqualsInsteadOfAssertTrue: This rule detects JUnit assertions in object equality. These assertions should be made by more specific methods, like assertEquals.
- UseAssertSameInsteadOfAssertTrue: This rule detects JUnit assertions in object references equality. These assertions should be made by more specific methods, like assertSame, assertNotSame.
- UseAssertNullInsteadOfAssertTrue: This rule detects JUnit assertions in object references equality. These assertions should be made by more specific methods, like assertNull, assertNotNull.
- SimplifyBooleanAssertion: Avoid negation in an assertTrue or assertFalse test. For example, rephrase: assertTrue(!expr); as: assertFalse(expr);
Code Analysis Tools
It is quite picky, but it is possible and worthwhile getting zero errors.
However, there are some errors that it cannot catch. These relate to information that is lost when you compile. I've come across two examples.
First is imports (or using). It is very easy to get extraneous imports. The compiler removes them, and so FxCop cannot tell if they exist in the source code.
Secondly relates to comments. There are great applications like NDoc. NDoc takes code, strips out XML comments and turns into documentation. Javadoc is another example. However, it is possible to change the code, and not keep the documentation up to date. For example, there is no check the signature of the function matches the signature in the documentation. FxCop like tools cannot check, because the comments are thrown away.
Interestingly tools for Java like IntelliJ handle this. You need to search through the code and find out exactly which imports are used, and could they be simplified.
Should be part of any good IDE.
Wednesday, April 26, 2006
The Problem with Unit Testing
One issue with unit tests is the limited number of paths through the software the tests test. Secondly, I'm not convinced that writing the test first, is the best way of writing code.
Taking each of these points in turn. You can address part of the limit number of paths by combining a code coverage tool with your unit tests. If you don't get code coverage, you can add more tests. However, what you really need is something that tests all the time.
Secondly, writing the test first focuses on a particular case, not on producing a good abstraction or good code. If you are not careful, the code is produced to meet a particular test case, not the set of test cases, or even the set of possible data.I've worked for a long time with Eiffel, and it has the interesting feature of design by contract. This combined with unit tests takes things to the next level. A lot of people who comment on DBC, have never used DBC in practice.
First, you change the way you program. It isn't write unit test first, it is contract first. Then write code / unit test. The change of emphasis is produce code that covers all cases. All cases are defined by the contract. Now it becomes clearer what the test cases are. You need to exercise the cases defined by the contract. Whether you write the tests, or the code first doesn't matter. Importantly, if you run the code with assertion checking on, you are testing the contracts as you go. Instead of testing just specific cases, you get universal testing. It is far more powerful.
There are some other alternatives that I can see coming in the future. FxCop and other static code analyzers are getting more sophisticated. Software such as the proposed NStatic are also interesting. Combining these with DBC would make something really powerful. I can also see the day when run time analysis during testing feeds back into the static analysis
Saturday, April 15, 2006
Welcome
Subscribe to Posts [Atom]