Saturday, July 18, 2009

Better Annotation in Java Around a Testing Framework

Recently in a pet project, i got involved extensively with annotation in java. I wanted to create a testing framework in which unit tests are created based on given methods level annotations. The testing concept is similar to EasyMock, but rather than creating mock objects, i wanted to capture real objects during "runtime" and then create tests cases based on annotation and output/input parameters. By the way, with "Runtime" i don't mean production environment. When a QA or developer run (tests) the product, tests cases and its inputs are created and stored.

After clearing the concept in my mind, i decided to do a prototype. In the first prototype, i wanted to implement @AssertNotNull unit test case for method's input parameters and output value.

By deploying method level java byte code injection with javassist and a simple annotation (@AssertNotNull), unit tests are create for methods and inputs and outputs of methods are serialized. Once i catch the input objects (parameters of the method) with injected byte code at the beginning and end of methods, i serialized them in XML format with XStream . Injected byte codes also call a TestGenerator service to generate unit tests based on the defined annotation and serialized input/outputs. In unit test phrase, I was planning to deserialize these input objects and uses as input to automatically created tests. First prototype was successful. Unit tests (@AssertNotNull) are created for output object and input parameters of a given annotated method. It was a big step to create unit tests automatically with real object rather than mock objects like EasyMock.

As a next step, i decided to implement a prototype for more complex test cases which has two inputs, for example @AssertEquals. When i was prototyping @AssertEquals annotation, i noticed that annotation in java are really so basic. They do not provide so much functionalities for advance usage such as:

  • Hierarchy: One of the main concept in OO is missing in annotation creation.You are not allowed to extend an annotation. For example, i would like to create a base annotation type (let say @Test) and many sub annotation types (@AssertTrue, @AssertNotNull, @AssertEquals) which extend @Tests. This approach, Hierarchy in annotation, would save lots of computation and coding time if reflection is used to probe which methods are annotated with a type of annotation (@Test) rather than a specific annotation (@AssertTrue). Of course, as a solution to lack of Hierarchy in annotation, methods or classes can be annotated both with super type and specific type annotation (both for example, @AssertNotNull and @Test). But isn't it an ugly code ?
  • Multiple annotation: A method or class can be annotated only once with a specific annotation. Even it is not much common in real life, as in my test framework, it should be possible to annotate a method with different parameters. For example, i would like to annotate a method with multiple @AssertNotEqual each of which uses different parameters. People who comes cross that issue, generally creates a container annotation For example in JPA, If you would like to annotate an entity with multiple @NamedQuery, you have to declare these annotations in @NamedQueries.
  • Simple Type : Types of fields in annotation are so restricted. Only primitive, String and Class types are allowed.
I think annotation in java should be revised. Similar to enums they should to be enhanced for a versatile and advanced usage. I am aware that these issues can be resolved with some other ways as i mentioned above, and it is not trivial to implement comprehensive annotation, but i still think that java deserves better annotation design.

By the way, i am still working on this pet project, test framework! Once i finished it, i will create a blog here with more detail.

No comments: