Auto-Unit-Test-Case-Generator automatically generates high-level code-coverage JUnit test suites for Java, widely used within the ANT Group.
NOTES FOR DEVELOPERS
These notes are meant for developers working on SmartUt.
There are several rules of thumb regarding how to write “good code”,
but often rules are either too generic and not tailored for a given particular
piece of software (e.g., different kinds of architectures).
The rules of thumb described here in this document are not meant to be either exhaustive nor absolute.
Rigid rules are not substitute for common sense, as they are rather guidelines that can
be ignored in some special cases.
Furthermore, the guidelines need to be realistic and easy to use: there would be no point
to ask for detailed comments on each single method/field and 100% coverage test suites…
AVOID System.out AND System.err
SmartUt uses a logging framework, in which client processes do communicate with Master through TCP.
For debugging and logging errors in a class Foo, create a logger in the following way:
private static Logger logger = LoggerFactory.getLogger(Foo.class);
It is important to keep the same name ‘logger’ to make things consistent among classes.
If the logging should be part the actual output for the console user, then rather use:
LoggingUtils.getSmartUtLogger()
AVOID String concatenation in Loggers
writing something like:
logger.debug(“this is not “+ foo + " very " + bar +” efficient”);
is not efficient, as most of the time debug logs are deactivated, and concatenating strings is
expensive. Recall String is immutable, and each “+” create a new String object.
The above logging can be rewritten into:
logger.debug(“this is not {} very {} efficient”, foo, bar);
Note: not a big deal for “warn”/“error”, as those are/should be rare… but it can become
quite an overhead for trace/debug/info
SmartUt should be DETERMINISTIC
SmartUt uses randomized algorithms. However, given the same random seed, the behavior should be
fully deterministic. This is essential for debugging SmartUt. Unfortunately, there are few libraries/APIs
that are non-deterministic, like for example HashMap and HashSet. Rather use equivalent classes that
are deterministic, ie LinkedHashMap and LinkedHashSet.
Note: we have system tests to check if SmartUt remains deterministic, eg see BaseDeterminismSystemTest.
DO NOT USE System.exit
Better to throw an exception, as the entry point of SmartUt does some logging when ends.
Furthermore, System.exit becomes problematic when unit testing SmartUt.
STATIC VARIABLES ARE YOUR ENEMY
Static variables should be either constant or representing transient data (eg cache information whose presence/missing
has only effect on performance, not on functionality).
Having “classes with states” is usually a poor OO design (an exception to this rule is org.smartut.Properties).
If those are really needed, then you should rather use a singleton pattern.
This is not just to be pedantic, but, really, non-constant static variables make unit testing far much harder
and lead to code that is more difficult to understand and maintain.
HOW TO WRITE JUNIT TEST CASES
Until SmartUt will not be applicable to itself, there is the need to write manual test cases.
They should be put in the “src/test/java” folder, following the same package structure as SmartUt code.
A unit test suite for SUT org.smartut.somepackage.Foo should be called org.smartut.somepackage.FooTest.
This is useful for several reasons:
If for testing there is the need to create additional, support classes used as data input for SmartUt,
then those will need to be put in the com.examples.with.different.packagename package.
AVOID TOO LONG METHODS
Too long methods (eg more than 100 lines) should be split, as difficult to understand.
For this task, in Eclipse, you can right-click on a code snippet and “Refactor -> Extract Method…”
WRITE COMMENTS
In the ideal world, each class/method/field would have nice, detailed, appropriate code comments.
But even in such a beautiful world, everything would go to hell at the first code change, as that might
require manually changing most of the code comments.
Cannot really quantify how much comments one should write, but at least it would be good to have:
When writing a comment for a class/method/field, use JavaDoc style:
/**
*/
In this way, tools like Eclipse will show the comments when you hover with the mouse over them.
IF CANNOT AVOID EXTERNAL SIDE-EFFECTS, DO DOCUMENT IT!!!
If a call on a object has side-effects outside the class itself (eg writing to disk, add a system hook thread),
then this needs to be documented (see point on how to write comments).
PRE and POST CONDITIONS
FIELDS/CONSTRUCTORS/METHODS ORDER IN A CLASS
when writing a new class (or re-factoring a current one), fields should come first, followed by class constructors and then the other methods.
HOW TO MAKE A RELEASE
To use the Maven plugin, and to link the “runtime” jar (plus dependencies)
to a project, SmartUt needs to be released and deployed on an accessible
repository.
Assume current SmartUt version is x.y.z-SNAPSHOT. You need choose
a new version number (x for major, y for minor, and z for patch).
Once chosen a new version a.b.c (with no SNAPSHOT, and it is fine to
have a.b.c == x.y.z), create a new Git branch with name equal to this
new version number.
Then, from command line execute:
mvn versions:set -DnewVersion=a.b.c
This command will go through all the pom files in the project, and replace
the version numbers there with the new one.
Commit and push the changed pom files.
To deploy to Maven Central, execute:
mvn clean source:jar javadoc:jar gpg:sign -PsignJars -DskipTests deploy
Note: this requires that you have configured GPG on your machine with the right
valid keys.
If the “Deploy” job ends correctly, then the new release has been deployed.
It might take up to 2 hours before it will be visible on Maven Central.
Now, on the Git master branch, need to set a new SNAPSHOT version:
mvn versions:set -DnewVersion=a.b.(c+1)-SNAPSHOT
(eg, here we just incremented the patch number by one).
Commit and push the modified pom files.