|
JRunr
Jrunr - Java Record Unit test data N Replay/ReuseTable of Contents:
ConceptsWhat is jrunr?jrunr is a tool that can be used to non-intrusively record and store unit test data from a running instance of an existing java application, which can be reused later on in unit tests. It is specifically intended for use in maintenance scenarios of java applications that are not TDD aware, which as a result cannot be easily unit tested. WhyUnit tests play a role in not just from-scratch development projects, but also in maintaining existing applications by providing the test base that can be used to validate new builds, ie, enhancements. However, adding to existing code that is not written in a test-aware fashion makes it difficult to narrow creation of any new test cases to the specific problem that is being fixed. Some of these scenarios are:
2. The code to be tested depends on a rather costly setup of other objects 3. The code to be tested depeneds on calls to other layers/applications, which are not (desirable to be) available in the unit test scenario.The traditional methods of attacking these problems is to mock out everything except the ["System under test"] (todo: link to xunit here). However in scenarios 2 and 3 above, the mocking approach might lead to an overly-complex mock layer or mock-calling-mock situation. Jrunr aims to avoid this, and provide an easier (if hackish) way of increasing legacy app test creation efficiency. It is not intended to replace test driven development or mocking; more to complement them in situations where the cost of elegance is too high :) Jrunr itself, however, aims to be an elegant tool, and therefore does all its work without any change to application code. How it worksJrunr is implemented as two compoents:
User GuideRequirementsInstallationInstallation in a Web Container
Installation in a standalone appInstallation in an EJB Container - TBDUsing jrunrDeciding what to record and how<Usage scenarios go here>Configuring the methods to record data fromRecording dataUsing the data in your unit testsDev guide/notesRequirements/Feature List
This requirement is to be fleshed out. The general idea, however is to use the recorded data as a template to generate more data either for functional tests, or for load testing. Project Roadmap
Status
AnalysisThe implementation will need solutions for the following sub problems:
Each is detailed below:
Issues# The current statement of requirements and its implementation are premised on the assumption that its sufficient to store the input and output data of method calls for purpose outlined in the Why section. Need to see if there are real world scenarios different from this. # Is the DataGen requirement valid? Status10/6/2007
Architecture/DesignSince the tool is intended for minimally invasive use, the Spring IoC container is chosen as the base framework. This also has the advantage of an installed base of applications, and declarative configuration. The tool itself clearly should comprise of two components:
In future other spring features such as MVC and WebFlow can be used to create an Admin UI. JSON is chosen as the storage data format as its lightweight, easier to read, and support for reading and writing it are readily available. DesignPackage DesignAll jrunr code will be created under the org.vinodkd.jrunr package. Subpackages aspect and data will contain the Recorder Aspect and the Data Access code respectively. A dummy application is currently bundled in the source under the com.acompany.sut package with a single class called CUT (for Class under Test). Test code for Jrunr will be created in the same package structure and namespace, but in a differnt source file tree. The Recorder AspectThe Recorder Aspect will be implemented in the org.vinodkd.jrunr.aspect.Recorder class. It will be a normal Spring bean with properties injected via spring config. It will support the setting up of method configuration and an output dir for generated json files. Class Prototype: public class Recorder
{
public void setRecordMap(Properties whatToRecord);
public void setOutputDir(Resource outputDir);
public void recordValues(ProceedingJoinPoint jp);
}Setting the recordMap attribute should power Recorder up with a list of methods to intercept and record. Setting the outputDir attribute should setup the directory that recordValues() will use to output json files. recordValues() will internally use the DataAccess API to write a Java Object as a json file. The DataAccess APIThe DataAccess API consists of 2 classes: JrunrStore a MethodExecutionRecord. MethodExecutionRecord is a value object and will contain the method name, and its input and output values. Like so: public class MethodExecutionRecord
{
private String methodName; // the fully qualified method name
private Object args[]; // the arguments
private Object retVal; // the return value
// setters and getters
}JrunrStore will provide convinent load and store operations using MethodExecutionRecord objects, like so: public class JrunrStore
{
public static void store(File f,MethodExecutionRecord mer);
public static MethodExecutionRecord load(File f);
}ConfigurationUser ConfigurationUsers of jrunr will configure it to define the methods they're interested in recording like so: <fully qualified class name>.<method name> = ARGS| RETURN | BOTH As is obvious, setting a method to ARGS will record only its input args, RETURN will record only its return values, and BOTH will record both. This configuration should be in a file called jrunr.properties. Internal ConfigurationThe tool internally will use spring configuration. The Recorder Aspect and DataAccess will be configured like so: <bean id="recorder" class="org.vinodkd.jrunr.aspect.Recorder"> <property name="recordMap"> <util:properties location="classpath:jrunr.properties"/> </property> <property name="dataStore" ref="dataStore"/> </bean> <aop:config> <aop:aspect ref="recorder"> <aop:pointcut id="theExecutionOfAMethodUnderTest" expression= " execution(* com.acompany.sut.*.methodToTest(..)) or execution(* com.acomp.sut.*.testMethod(..)) " /> <aop:around pointcut-ref="theExecutionOfAMethodUnderTest" method="recordValues"/> </aop:aspect> </aop:config> <bean id="dataStore" class="org.vinodkd.jrunr.data.JrunrStore"> <property name="location" value="file:E:/vinod/projects/JRUNR/out"/> </bean> Tools/libraries used
Issues/todos# The schema-based spring AOP doesnt allow for configuration of both the Recording Advice and the Recorder Aspect from the same list of method names. The current implementation, therefore, requires the user to configure this list in two places, which is against the DRY(todo: link here) principle. Reporting to the spring forum has brought the suggestion of writing a custom pointcut implementation. Consider this, or consider use of the Regex based Spring Advisor which should do the same thing. Status10/6/2007 todo: finish design doc ConstructionIssues/todos# Externalize user configuration to props file. # Create dataaccess api objects # Correct Boot and Recorder to use dataaccess # Try out the RegexAdvisor Status10/8/2007 Have working code for the Recorder and Dataaccess; but latter is not still refactored into separate code. Need to try it on real code. Project ManagementIssues/Todos# Setup SCM - done # Add use of savant for dependent libraries # Create sf project StatusFAQ# Why not jdk 1.5 # Why not aspectj ColophonThis document uses the Markdown(todo:link here) syntax. | ||||||||||||