Skip to main content
| Mission Statement | Background | Example | Demos |Installation and test result | Links

Mission Statement

JEasyTest is an Eclipse 3.3 IDE plugin created to simplify unit testing of code that is hard to test using standard mock objects frameworks, as for example code using legacy code. JEasyTest uses AspectJ load-time bytecode modification "to inject mock invocations" (constructor and static method invocations) in which we are not allowed to use standard mock object tools (this technique is also known as Virtual Mock Objects).

JEasyTest has been thought to be integrated with existing mock object frameworks to overcome some of their limitations. Throughout a literate API, the border between the code under test and the test itself nearly disappears and the concept of endo-testing is moved a step forward: the testing context, and only this, becomes a privileged environment from where we can set expectations as if we were inside the code to be tested.

In JEasyTest the bytecode of our classes is modified only at runtime just before test running, without any possibility that production code might contain unwanted testing code. Thanks to the Eclipse plugin nature, JEasyTest usage of AspectJ is completely hidden and it happens behind the scenes while we are writing tests.

Background

Writing software is a hard task. Concepts like low coupling, high cohesion, separation of concern, modularization, coding in terms of interfaces rather than implementations, "tell, don't ask" principle, dependency injection, refactoring and many more should never be forgotten.
By using mock objects, writing unit tests for code implemented following these principles is not a difficult task. By following a Test Driven Development approach we can even write code that is tested and at the same time create a system where collaboration and relathionship between objects are explicit.

Problems arise when our code has dependency with legacy code. Testing code that uses static methods or direct object instantiations can not be done straightforward using mock objects. Of course, if we use the principles mentioned above, we can create layers in which to confine this legacy code in a way that the whole system becomes easy to test, although sometimes refactoring can be larger than our initial task.

Sometimes even if we start from scratch, apply those principles could be not so easy, or not dictated by business requirements: overdesign can be as dangerous as underdesign. To be practical, should I always write an interface instead of writing a concrete implementation, even if I am not thinking about an important service functionality that affects all modules of my system?
For example, given a class A, can I afford writing a concrete implementation C, with a friendly package visibility that interacts with A (inside A I would like to write new C(..)) without losing the possibility of testing A in isolation (using a TDD approach), mocking new C(..)? After all, this can be a sort of encapsulation, another important software concept.
Can I afford using, inside A, static methods of a third party library to delete a directory or to read a system property without creating other interfaces or classes and meanwhile be able to test A in isolation without delegating to the real static method implementation?

JEasyTest has been created to solve this kind of problems, in an easy way. Using a simple literate API and a TDD approach you can set expectations for static method and constructor invocations and test your code in isolation.
JEasyTest uses AspectJ but you do not have to know AspectJ to use JEasyTest.
It is worth to point out that using programming principles mentioned previously should never ever be forgotten, and the fact that JEasyTest offers a possibility of mocking static methods, for example, it is not a reason for ignoring OOP principles. Use JEasyTest in a judicious way.

An Example

Here is a simple example of test written using JEasyTest:

@ClassUnderTest(MyServiceClient.class)
public class MyServiceClientTest extends TestCase {
	@JEasyTest
	public void testRunThrowsIllegalStateExceptionIfInitialContextThrowsNamingException() throws Exception {
		on(System.class).expectStaticNonVoidMethod("getProperty").with(arg("objectName")).andReturn("test");
		on(InitialContext.class).expectEmptyConstructor().andThrow(new NamingException("message"));
		
		MyServiceClient client = new MyServiceClient();
		try {
			client.run();	
			fail(IllegalStateException.class+" should have been thrown");
		} catch (IllegalStateException e) {
			assertEquals("message", e.getMessage());
		}
	}
}
where
public class MyServiceClient {
	public void run() {
		String objectName = System.getProperty("objectName");
		if (objectName == null){
			throw new IllegalStateException("Object name system property must be defined");
		}
		try {
			InitialContext context = new InitialContext();
			Service service = (Service)context.lookup(objectName);
			service.doThis();
		} catch (NamingException e) {
			throw new IllegalStateException(e.getMessage());
		}
	}
}

Release 200711041605

The following demos show JEasyTest new features:
  • 1) Eclipse 3.3 support (Eclipse 3.2 is not longer supported).
  • 2) JUnit 4 support.
  • 3) Expectations can be set on the class under test.
  • 4) JEasyTest has now an Ant task to be used outside Eclipse.


JEasyTest JUnit4 and ClassUnderTest expectations(2.5MB 3 minutes)

JEasyTest Ant task(0.4MB 2 minutes)

Release 200708171059

In the demos below the following feaures are explained:
  • 1) First of all, when a project becomes a JEasyTest project, the jeasytest/generatedAspects directory containing the generated aspects is not longer included as source directory of the project: this directory will be included in the classpath of the running test only. In this way the bytecode modification happens only when it is strictly required: before run tests.
  • 2) Now JEasyTest generates aspects files as .class files (JEasyTest creates bytecode directly) rather than .java annotation style aspects as the previous release.
  • 3) Now each JEasyTest test is decorated with a particular icon so we can recognise a JEasyTest test from other tests immediately from the navigator Eclipse view.
  • 4) Now JEasyTest can be used in an AspectJ project.



JEasyTest new features(2MB 2 minutes)

What makes a test a JEasyTest(0.7MB 1 minute)

JEasyTest in an AspectJ project(1MB 2 minutes)

Release 200705181110

The following demonstrations show in every detail how to use JEasyTest. They have been organised to be watched in sequence. Click on the image to start the demo.




First steps with JEasyTest: in this first demo (about 2.8MB 7 minutes) I describe how to add JEasyTest capability to a java project and how to write a simple test using JEasyTest.

Advanced features of JEasyTest: in this second demo (about 4MB 10 minutes) you can see advanced features of JEasyTest. The test case written in the first demo will be extended and other characteristics of JEasyTest will be explained.

How JEasyTest works: in this demo (about 2.2MB 5 minutes) I describe in details how JEasyTest works, what happens behind the scenes.

Installation and tests result

To install JEasyTest plugin in your Eclipse 3.3 installation (PS: Eclipse 3.2 is no longer supported):
  • Shutdown Eclipse
  • Download last release and move the jar into your Eclipse plugins directory
  • Launch Eclipse (using the -clean command line argument when starting up Eclipse can solve problems due to stale plugin cache information.)
To use JEasyTest Ant task you need the following jars (please have a look to demos for all the details) To download the source go to the SVN repository. To retrieve other useful information you can go to the following link:

Links

 
 
Close
loading
Please Confirm
Close