Friday, October 22, 2010

Performing Unit Tests with the @Inject Container as a Runner

As a response to the following post about the "Perfect Integration Test" i would like to give my point of view of what a perfect test with active connection to a database is. Jboss Blogg entry

The following has a big difference to the Arquillian project, it never intends to be able to execute the same testsuites on different container vendors. Its more focused on creating the fastest and simplest possible UnitTest for your EJB code.

But I must admit that a lot of my inspiration to do this came from Arquillian, i just thought they had the wrong focus.

I will explain how its possible to perform a UnitTest where the following rules are enforced.

  1. The services are "wired" for EJB3 (Stateless/Stateful Sessions Beans supported) automatically with a scanning path configuration.
  2. For each test the "container" is automatically reset
  3. For each test the internal database is rolled back
  4. Its possible to register mocking services by overriding existing configuration, to make it easier to vary the test-suite without reconfoguring the entire software with a new "config class".


All these feature's are enabled with the help of the hrodberaht injection container and an extension to it called ejbunit (might be renamed to just junit as i am thinking about adding spring support as well, as it feels easy enough).
Injection Wiki (the 1.2-SNAPSHOT version though is needed, as its in this version that the cloning support is added)

This is done using the followign techniques.

1. The services are "wired" for EJB3 (Stateless/Stateful Sessions Beans supported) automatically.
- All that is needed is a JUnitRunner and a Project Configuration (scanners are supported)

2. For each test the "container" is automatically reset
- The container is resets to its original state before the test is executed. Original is whatever the config found in the class Project Configuration context.

3. For each test the internal database is rolled back at the end
- All calls to close/commit are prevented (silently) and a rollback is executed once the testsuite is over.
- Works as long as the datasource is created by the Project Configuration

4. Its possible to register mocking services by overriding existing configuration, to make it easier to vary the testsuite without reconfoguring the entire software with a new "config class".
- Is done using a utility that can reach the running @Inject Container for the active test. (supports several active test threads if needed)

So how does this look code wise:
The test
@EJBContainerContext(EJBContainerConfigExample.class)
@RunWith(EJBJUnitRunner.class)
public class TestEJB3ServiceContext {

    @EJB
    private EJB3ServiceInterface ejb3ServiceInterface;

    @Test
    public void testEJBWiring(){
        String something = ejb3ServiceInterface.findSomething(12L);
        assertEquals("Something", something);

        String somethingDeep = ejb3ServiceInterface.findSomethingDeep(12L);
        assertEquals("Something Deep", somethingDeep);
    }

    @Test
    public void testEJBResourceInjectionAndUpdate(){
        String something = anInterface.findSomethingDeepWithDataSource(12L);
        assertEquals("The Name", something);
        anInterface.updateSomethingInDataSource(12L, "A new Name");
        something = anInterface.findSomethingDeepWithDataSource(12L);
        assertEquals("A new Name", something);
    }

    @Test
    public void testEJBWiringWithMockito(){

        EJB3InnerServiceInterface anInterface =
            Mockito.mock(EJB3InnerServiceInterface.class);
        Mockito.when(anInterface.findSomething(12L))
            .thenReturn("Something Deep FormMock");
         EJBResourceHandler
             .registerServiceInstance(EJB3InnerServiceInterface.class, anInterface);

        EJB3ServiceInterface serviceInterface =
             EJBResourceHandler.getService(EJB3ServiceInterface.class);
        String something = serviceInterface.findSomething(12L);
        assertEquals("Something", something);
        String somethingDeep = serviceInterface.findSomethingDeep(12L);
        assertEquals("Something Deep FormMock", somethingDeep);
    }
}

So what is all this:
1. The config @EJBContainerContext(EJBContainerConfigExample.class)
- This contains the code that "scans" for all EJB's in the software, using package scanning. This is similar to the annotation @Deployment used by Arquillian.

public class EJBContainerConfigExample extends EJBContainerConfigBase {

    public EJBContainerConfigExample() {
        String dataSourceName = "DataSource";
        addResource(dataSourceName,
             ResourceCreator.createDataSource(dataSourceName));
        addSQLSchemas(dataSourceName,
            "test/org/hrodberaht/inject/extension/ejbunit");
    }

    @Override
    public InjectContainer createContainer() {
        return createAutoScanEJBContainer(
             "test.org.hrodberaht.inject.extension.ejbunit.ejb3.service");
    }


- "addResource" Will register a  datasource for the application named "DataSource", this works as any datasource and can be injected with @Resource as regular with EJB3.
- "addSQLSchemas" Will try to execute all SQL files found in this directory names with "create_schema*" once all those are executed all file with the name "insert_data*" will be executed. This execution results will be commited to the datasource selected in the method call.
-  "createContainer" A container will be created and returned (this is used by the Runner)

2. @RunWith(EJBJUnitRunner.class)
This will take care of all the gritty details with rollback of the active connection and reset of the "container".
Before a testsuite is executed a clone of the container is made and registered as the active container for the running test (after the original has been created from the Configuration).

3. @EJB private EJB3ServiceInterface ejb3ServiceInterface;
All testclasses that have the RunWith can have injected Service (both @EJB and @Inject works)

4. The tests themselves
Are not that special, only that they can be be executed without any before/after handling for rollback or cleanup of the database.
4.1 testEJBWiring
The test for this will only verify that the injection have done what they are suppose to.
4.2 testEJBResourceInjectionAndUpdate
The test will verify that
- the SQL scripts have been executed (first row is a selection of the id 12)
- the Datasource has been injected correctly to the inner service bean
- that the update code works as intended and can be refetched from the running database.

Note: In the real test suite a second test is execute to verify that the update is automatically rolled
back by the testrunner.

All this code can be found in extensions to the hrodberaht @Inject. At the google code projects.
http://code.google.com/p/java-simple-utils/
http://code.google.com/p/injection-extensions/

The code for the test case used as example here can be found at:
http://code.google.com/p/injection-extensions/source/browse/trunk/ejbunit/src/test/java/test/org/hrodberaht/inject/extension/ejbunit/ejb3/TestEJB3ServiceContext.java

A simple example POM file for anyone that want to test this has been committed to the test suite.
http://code.google.com/p/injection-extensions/source/browse/trunk/ejbunit/example-pom/pom.xml
PS: I have not verified the POM on another computer so please report any problems if you try it.

Sunday, September 19, 2010

JSR 330 and @Inject

The background (why the hell create a new IoC DI framework)
First of i would like to explain that the initial intention from my side was to create a very simple InjectionContainer that could extend Spring/Guice when needed and be replaces as soon as Spring/Guice released their version that supports JSR-330.

After waiting and not understanding how and when Spring and Guice was actually going to do this I started to play with the JSR 330 TCK. Once the TCK was implemented with the @Inject IoC I realized that this is quite powerful and that I wanted and needed extensions for it to be useful in a real world application.

The primary reason for this research from my side was to get a deep understanding of IoC DI and to finally implement a generic solution of the many "simplifications" I have always created in a application when I start to develop for a customer.

Basic project info/note
I am a Maven2 addicted developer (its not all good but its worth it in the end), so all projects are Maven'ized and all releases are deployed to central Maven repository (thanks to Sonatype).

Release 1.1.0 of Simple Java (with Config/i18n and Inject implementations bundled)

The Different projects

- Config
Java properties has been the same for ages and are very not very useful. This is an extension to those properties with Generics and override (via System parameters) support.
- i18n
Java Format packages has a lot of features but they are sometimes hard to "find" and use in a good way. This package does that, it gathers the formatters and configures them in a more useful way. And it also fixes an irritating bug that Sun refuses to solve with the wrong blank-space being used as a thousand separator.

- @Inject (the org.hrodberath.inject)
The Injection framework implementation is a certified (not official yet though) version of the JSF 330 specification. The TCK test suite can be found in the code base.

The @Inject framework today implements a small but similar feature set to Guice

Current feature set (in release 1.1.0)
  • support for new and singelton scope
    - also thread and inheritable-thread but these are custom
  • support for javax.inject.Provider (very useful interface)
  • support for configuration of older non @inject friendly factories via the InjectionFactory
  • Has extensive registering support (with "inheritable" modules), this is the intended strong point of this framework.
    - Has scanning support
    - Has module "extends" support (like inheritance)
    - Simple System.out printing of active configuration
Planned additions (in release 1.2.0)
  • support for attaching older non @inject friendly variable factory via a VariableInjectionFactory
  • SPI support for adding custom @Inject and @PostConstruct and @Scope annotations
  • Service Configuration live exporting to XML
  • More and better support for multi module configuration "mixing" where the exact results of these mixes can be seen and understood easily.
    - Implement the @Extends annotation that was added in 1.1
    - Support multiple "extends" (multi inheritance)
    - Support advance configuration where support for standard / customer / custom variations are supported and easy to understand how to configure. Add some way to switch between these config variations.
- Extensions for @Inject (the org.hrodberath.inject.extension)
I have planned the following extensions for release soon.

Ongoing features (Has SNAPSHOT code that is close to working as intended)

Transaction (JDBC and JPA support, not JTA or XA)
  • Uses EJB annotations with AspectJ
  • All transaction types from EJB implemented and supported
  • JPA --> JDBC shared connection support implemented
  • JDBC Helper package included
  • Junit Runner
    - Transacted and Container manager runner implemented
  • TODO: create more test suites for mixed transactions
JSF (@Inject and Transaction supported JSF with no-config setup)
  • JSF Injection Provider for @Inject implemented
  • OpenTransactionInView via a Filter is implemented
  • TODO: no config, need inspiration here: use a Annotation? naming?
Planned features (has no SNAPSHOTS or source code at this moment)

EJB 3.0 JUnit Framework (with Mocking help connected to mockito)
  • Extreme bootstrap speed (less than 1s for a standard project with 100 services or so)
  • @Inject and Transaction support for an EJBJunitRunner built on @Runwith
  • Support for @EJB and @Resource
    • Not entitys, use hypersonic with JPA for this, its loads simpler.
NetBeans RCP
  • @Inject and Transaction support
Eclipse RPC
  • @Inject and Transaction support
GWT (still unsure if this will be supported, as I don't "get it" GWT at this moment)
  • @Inject and Transaction support
Spring

Connect the @Inject container to Spring managed beans to support the usage of any Spring bean inside the container.
  • JMS Bean usage support verified
  • WebFlow beans support verified
  • RMI Bean usage support verified
Example Application for JSF (built on the superb JSF framework PrimeFaces)

This is intended as the showcase to prove that the coding can be done very fast and simple.
Points to sonatypes snapshot repository for the snapshot dependencies.
Usage examples

All projects are syncronized to central Maven and can be used without a extra addition of repository. Snapshots need the sonatype repository though,
https://oss.sonatype.org/content/repositories/snapshots/

See http://code.google.com/p/java-simple-utils/

Simple Java Config


public class AnyApplicationConfig extends ConfigBase {
private static final String DEFAULT_CONFIG = "classpath:/basicConfig.properties";

public static void initConfig() throws ParseException {
    initConfig(DEFAULT_CONFIG);
}
public static void initConfig(String resource) throws ParseException {
    String externalConfig = System.getProperty("config.externalfile");
    if(!StringUtil.isBlank(externalConfig)){
        // This initilized (reads) the config
        new AnyApplicationConfig(resource, externalConfig);
    }else{
        // This initilized (reads) the config
        new AnyApplicationConfig(resource, null);
    }
}

public interface ApplicationState {
    ConfigItem<String> A_STRING = new ConfigItem<String>(String.class, "anyapp.astring");
    ConfigItem<Date> A_DATE = new ConfigItem<Date>(Date.class, "anyapp.adate");
    ConfigItem<Integer> A_INTEGER = new ConfigItem<Integer>(Integer.class, "anyapp.ainteger");
    ConfigItem<Long> A_LONG = new ConfigItem<Long>(Long.class, "anyapp.along");
}


Simple Java i18n
Wiki Guide: http://code.google.com/p/java-simple-utils/wiki/i18n

// This mimics what can be done in a software using the profile provider.
Locale testProviderLocale = new Locale("en", "US");
LocaleProvider.setThreadLocaleProvider();
// This mimics what can be done in a RequestFilter for example
LocaleProvider.setProfile(new LocaleProfile(testProviderLocale));
// All calls to the provider from now on in the current thread will return this locale
LocaleProvider.getProfile().getLocale();

// The following code would now follow this locale
String testDate = "2010-01-01";
Formatter<Date> formatter = Formatter.getFormatter(Date.class);
Date aDate = formatter.convertToObject(testDate);
String aStringDate = formatter.convertToString(aDate);


Simple Java Injection (@Inject)
Wiki Guide: http://code.google.com/p/java-simple-utils/wiki/Injection
JSR 330 Annotation supported Container Configuration example:

InjectionRegisterJava registerJava = new InjectionRegisterJava();
registerJava.register(new RegistrationModuleSimple() {
    public void registrations() {
        register(AnyService.class).annotated(DoNothing.class)
            .scopeAs(ScopeContainer.Scope.SINGLETON)
            .with(AnyServiceDoNothingImpl.class);
        register(AnyService.class)
            .registeredAs(SimpleInjection.RegisterType.FINAL)
            .with(AnyServiceDoSomethingImpl.class);
    }
});

JSF and JUnit example setup with Injection support

@InjectionContainerContext(ModuleContainerForTests.class)
@RunWith(InjectionJUnitTestRunner.class)
@TransactionAttribute
public class TestJPATransactionManager {

    @Inject
    private TransactedApplication application;
...
}



The details about this code is
1. @InjectionContainerContext
- This is the InjectionContainer JUnitRunner Container Context
2. @RunWith
- This is the JUnit annotation that connects the Container to JUnit and adds transaction support when needed.
3. @TransactionAttribute
- This is the EJB3 annotation and it activates transaction support for all tests in this class. InjectionJUnitTestRunner is the class that actually does this.

A JSF Bean with Injected services

@ManagedBean(name = "personBean")
@RequestScoped
public class WebInjectBean {

    @Inject
    private ServiceInject serviceInject;
}


Config in web.xml for this to work
<context-param>
<param-name>com.sun.faces.injectionProvider</param-name>
<param-value>org.hrodberaht.webexample.web.ApplicationJSFResolverImpl</param-value>
</context-param>


A very simple example Application with the Injected transaction manager for a JPA configured application.
See the Google Code link

public class JPATransactedApplication implements TransactedApplication {

    @Inject
    private Provider<EntityManager>

    @TransactionAttribute
    public void createPerson(Person person) {      
        EntityManager em = entityManager.get();
        em.persist(person);
    }
}


The Application with the Injected transaction manager for a JDBC configured application.
See the Google Code link

public class JDBCHelperApplication {

    @Inject
    private JDBCService jdbcService;
  
    public void createAdvancedModel(AdvanceModel advanceModel) {
    Insert insert = jdbcService.createInsert("advanceModel");
        insert.field("id", advanceModel.getId());
        updateAllFields(advanceModel, insert);
        jdbcService.insert(insert);
    }

    public AdvanceModel findAdvancedModel(Long id) {
        String sql = "select * from AdvanceModel where id = ?";
        return jdbcService.querySingle(sql, new AdvanceModelIterator(), id);
    }
    ...
}


Example configuration from the proof of concept project
See Google Code link

InjectionRegisterScan registerJava = new InjectionRegisterScan();
registerJava.registerBasePackageScan("org.hrodberaht.webexample.service.impl");

InjectionRegisterModule register = new InjectionRegisterModule(registerJava);
final TransactionManager transactionManager =
new TransactionManagerJPAImpl(Persistence.createEntityManagerFactory("web-example-jpa"));
register.register(new TransactionManagerModule(transactionManager, register));


Sunday, May 30, 2010

Simple Java soon ready for 1.0 release.

So I have finally found some time to code for this and have created almost all I need to feel like this is a real 1.0 release.

Done:

1. Changed name of simplecontainer (IoC) to SimpleInject (injection).
2. Divided the code into more modules (core, i18n, ejb2x, inject)
3. Inject: Added support for Injection (using javax.inject.*)
4. Inject: Added JSR 330 as a verification of the inject module (using the TCK tests)
- Thanks http://code.google.com/p/kouinject/ for the inspiration to do this.
5. Updated the Maven2 (pom's) to give a good report that I uploaded to google-code-svn (had some issues here, might talk about those in a seperate blogpost)

Left to do:

1. ejb2x: Finish the ejb2x module (servicelocator) or remove it.
2. Core: Write tests for the Core Util packages
3. Injection: needs more structure for and if it will "implement" Spring and Guice extensions.
4. i18n: Finish the formatters
5. i18n: Add language services for simpler usage of Formatter/LocaleProfile

Comments

It was a lot easier to create an injection framework than I though. The verification tests helped alot to realise how to actually perform the code and I also looked a lot on the Kouinject project (he had the same coding style as I do so it was easy to read, atleast compared to Guice and Spring IoC).

Wednesday, March 31, 2010

Private/Public project time

Well i have been away for a long time from this blog and the reason is i have done to many interresting Java experiences the last few years but forgot to share them :)

What have i done -- well, i have coded my first project doing it TDD. We did this using Java 1.5 SDK/Spring/JUnit/Clover. After about 3 months of struggling with the TDD concept the "click" finally came and I can no longer code without it ... and can't understand how I managed without it before.

From the experience of the TDD and JUnit came a bigger interest in the minor areas of Java code as when doing tests i can finally found them interesting enough to care ;)

This interest has now grown into two simplification and extension framework i will try to create as the normal way of doing this is not easy enough.

http://code.google.com/p/java-simple-utils/
http://code.google.com/p/spring-simple-extensions

Both these are about making a Java developers everyday easier and more effective.

I will create a few more posts some time soon on why these projects have been started.

This is just a notice that they exist.