Vasily Sizov. Funky life.

Blog of IT manager, Java EE architect and developer more...

Wednesday, April 18, 2012

New home page

I've just created a new home page at www.vasilysizov.com with my actual CV. Read more...

Tuesday, January 26, 2010

Step-by-step guide to JPA-enabled unit testing with TestNG, Unitils, DBUnit, EasyMock and in-memory RDBMS HSQLDB

The term «unit testing» means testing of some atomic units of code (usually some beans, some classes) in isolation from other parts of a system. My experience shows that a lot of time the code is just interaction with a database. That's why it is a good idea to have an ability of unit testing with a live persistence context.

This post contains a complete testing solution based on top of Unitils and included following products:

  • EasyMock — mocking framework which allows to create mock objects easily and use them within our tests. We use it to isolate our tested object from other parts of a system.
  • DBUnit — framework which allows us to set defined state of a database between tests. We use it when we perform database-related testing.
  • DBMaintain — utility which allows to control schema of a database including: generating, editing, migrating from version to version, etc. In our case we use it to prepare database schema for using with DBUnit.
  • TestNG — framework which provides basic architecture for out tests. You can easily switch to JUnit if you like.
  • Unitils — framework which integrates all of the enumerated technologies and provides tools to simplify testing.
  • HSQLDB — fast in-memory database to serve our database-related tests.

To grasp the concept let's take a look at the diagrams.

This first one displays the live environment of The Bean we are going to test.

The second one displays the testing environment.

Please note, you can still use your production DBMS within the test environment if your code depends on its proprietary features. All you need is to create another Persistence Unit and to define it within test. Greater details follow.

How to setup the test environment

I assume that you use Maven to build your project. First of all we should configure our project’s .pom properly.


<build>
    <testResources>
        <testResource>
            <directory>src/test/resources</directory>
        </testResource>

        <testResource>
            <directory>${basedir}/src/test/java/</directory>
            <excludes>
                <exclude>**/*.java</exclude>
            </excludes>
        </testResource>
    </testResources>
     
    …

    <plugins>          
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.5</version>
        </plugin>
       
        …

    </plugins>
</build> 

In this part of .pom we specify that Maven should place various resource files to target test directory (by default it places only .class files ignoring .xml, etc). We have to do it because DBUnit uses .xml files to determine data fixture. As you can see we also specify the latest version of Surefire plug-in to run TestNG/JUnit tests. Earlier versions of Surefire contain various bugs related to TestNG tests running.

What's next? We specify needed dependencies in Dependency Management. Then we should append dependencies to concrete module’s .pom.


<dependencyManagement>
    <dependencies>                                         
        <dependency>
            <groupId>org.unitils</groupId>
            <artifactId>unitils-dbunit</artifactId>
            <version>3.1</version>
            <scope>test</scope>
        </dependency>
        
        <dependency>
            <groupId>org.unitils</groupId>
            <artifactId>unitils-orm</artifactId>
            <version>3.1</version>
            <scope>test</scope>
        </dependency>
        
        <dependency>
            <groupId>org.unitils</groupId>
            <artifactId>unitils-dbmaintainer</artifactId>
            <version>3.1</version>
            <scope>test</scope>
        </dependency>
        
        <dependency>
            <groupId>org.unitils</groupId>
            <artifactId>unitils-easymock</artifactId>
            <version>3.1</version>
            <scope>test</scope>
        </dependency>
        
        <dependency>
            <groupId>org.unitils</groupId>
            <artifactId>unitils-testng</artifactId>
            <version>3.1</version>
            <scope>test</scope>
        </dependency>
        
        <dependency>
            <groupId>org.unitils</groupId>
            <artifactId>unitils-inject</artifactId>
            <version>3.1</version>
            <scope>test</scope>
        </dependency>
        
        <dependency>
            <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>5.10</version>
            <scope>test</scope>
            <classifier>jdk15</classifier>
        </dependency>
        
        <dependency>
            <groupId>hsqldb</groupId>
            <artifactId>hsqldb</artifactId>
            <version>1.8.0.10</version>
            <scope>test</scope>
        </dependency>
        
        <dependency>
            <groupId>oswego-concurrent</groupId>
            <artifactId>concurrent</artifactId>
            <version>1.3.4</version>
            <scope>test</scope>
        </dependency>       
    
        ...    
        
    </dependencies>
</dependencyManagement>

Note. At this moment there is a little problem with resolving of required jta-1.0.1B.jar dependency from main Maven repository. To solve it you have to download JTA 1.0.1B classes zip file from Sun’s site. Then install it to the Maven’s local repository with a command: mvn install:install-file -Dfile=./jta-1_0_1B-classes.zip -DgroupId=javax.transaction -DartifactId=jta -Dversion=1.0.1B -Dpackaging=jar
That’s it!

Now let’s configure persistence.xml to make our tests JPA-enabled. We don’t need to install HSQLDB separately -- It runs automatically during a testing phase. As mentioned earlier you can define another Persistence Unit or edit this one to use another data base.
Please notice, you have to list your entity classes manually.


<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
  version="1.0">
    <persistence-unit name="testPersistenceUnit" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <class>com.sizovpoint.entity.Tag</class>
        <class>com.sizovpoint.entity.Post</class>

        <exclude-unlisted-classes>true</exclude-unlisted-classes>
        <properties>
            <property name="hibernate.connection.provider_class" value="org.hibernate.connection.DriverManagerConnectionProvider" />
            <property name="hibernate.connection.url" value="jdbc:hsqldb:mem:unit-testing-jpa"/>
            <property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver"/>
            <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
            <property name="hibernate.connection.username" value="sa"/>
            <property name="hibernate.connection.password" value=""/>
        </properties>
    </persistence-unit>
</persistence>

Also we should place some configuration files to test resources directory:

unitils.properties file to configure Unitils:


# Defaults and other keys with explanations can be found there: http://unitils.org/unitils-default.properties
unitils.module.database.enabled=true
unitils.module.dbunit.enabled=true
unitils.module.hibernate.enabled=false
unitils.module.mock.enabled=true
unitils.module.easymock.enabled=true
unitils.module.inject.enabled=true
unitils.module.spring.enabled=false
unitils.module.jpa.enabled=true

database.driverClassName=org.hsqldb.jdbcDriver
database.url=jdbc:hsqldb:mem:unit-testing-jpa

database.dialect=hsqldb
database.userName=sa
database.password=
database.schemaNames=PUBLIC

org.unitils.core.dbsupport.DbSupport.implClassName.hsqldb=org.unitils.core.dbsupport.HsqldbDbSupport
org.dbunit.dataset.datatype.IDataTypeFactory.implClassName.hsqldb=org.dbunit.ext.hsqldb.HsqldbDataTypeFactory

dbMaintainer.script.locations=src/test/resources
dataSetStructureGenerator.xsd.dirName=target/xsd
dbMaintainer.autoCreateExecutedScriptsTable=true
dbMaintainer.fromScratchEnabled=true
updateDataBaseSchema.enabled=true

jpa.persistenceProvider=hibernate

The next one is database_schema.sql file which contains DDL SQL for database generation with DBMaintainer. For our example it contains the following:


create table Post (
    id bigint generated by default as identity (start with 1),
    title varchar(255) not null,
    content varchar(2000) not null,
    creationDate timestamp,
    primary key (id));

create table Tag (
    id bigint generated by default as identity (start with 1),
    name varchar(255) not null,
    primary key (id),
    unique (name));

create table PostsToTagsLink (
    id bigint generated by default as identity (start with 1),
    post_id bigint not null,
    tag_id bigint not null,
    primary key (id));

alter table PostsToTagsLink add constraint FKC1 foreign key (post_id) references Post;

alter table PostsToTagsLink add constraint FKC2 foreign key (tag_id) references Tag;

That's it! Let’s move on.

Example application to test

Let’s assume we have four classes:

CreatePost EJB is an entrance for post creating. Invoking public void create(String title, String content, String tagsNames); method with some title, content and string like «apple, red» creates and persists a new instance of the Post entity with related Tags. For working with Tags there is TagManager which responsible for persisting of new tags and resolving of already persisted ones. TagManager is used by CreatePost.

Summarizing the code looks like:


@Entity
public class Post {
    Long id;
    List<Tag> tags; // many-to-many association
    String content;
    String title;
    Date creationDate;
   
    … // getters & setters
}

@Entity
@Table(uniqueConstraints = {@UniqueConstraint(columnNames={"name"})})
public class Tag {
    Long id;
    String name;

    … // getters & setters
}

@Name("createPost")
@Stateless
public class CreatePostBean implements CreatePost {
    @In TagManager tagManager;
    @In EntityManager entityManager;

    public void create(String title, String content, String tagsNames) {
        List<Tag> persistedTags = tagManager.findOrPersistTags(tagsNames);

        Post post = new Post();
        post.setTags(persistedTags);
        post.setContent(content);
        post.setTitle(title);
        post.setCreationDate(new Date());

        entityManager.persist(post);
    }
}


@AutoCreate
@Name("tagManager")
@Stateless
public class TagManagerBean implements TagManager {
    @In EntityManager entityManager;

    public List<Tag> findOrPersistTags(String tagsNames) {
        List<Tag> tags = new ArrayList<Tag>();

        List<String> distinctTagsNames = getDistinctTagsNamesList(tagsNames);
        for (String tagName : distinctTagsNames) {
            tags.add(findOrPersistTag(tagName));
        }

        return tags;
    }

    public List<String> getDistinctTagsNamesList(String tagsNames) {
        List<String> names = new ArrayList<String>();
        StringTokenizer tokenizer = new StringTokenizer(tagsNames, ",");

        while (tokenizer.hasMoreElements()) {
            String foundTagName = tokenizer.nextToken().trim();
            if (!names.contains(foundTagName)) names.add(foundTagName);
        }

        return names;
    }

    public Tag findOrPersistTag(String tagName) {
        Tag tag;
        try {
            tag = (Tag) entityManager
              .createQuery("select t from Tag as t where lower(t.name) = lower(:tagName)")
              .setParameter("tagName", tagName)
              .getSingleResult();
        } catch (NoResultException e) {
            tag = new Tag(tagName);
            entityManager.persist(tag);
        }

        return tag;
    }
}

Please notice that I provide the code before tests only for better understanding. Good practice is to follow Test-Driven Development principles.

Testing

Let's begin with testing of all 3 public methods of our TagManager.

First of all we should prepare some fixture for the database. This is DBUnit feature. Fixture is written in XML. Let’s call it with some meaningful name. I prefer to give it the same name as for the test class – TagManagerTest.xml:


<?xml version='1.0' encoding='UTF-8'?>
<dataset>
    <tag id="1" name="Apple" />
    <tag id="2" name="Dog" />
    <tag id="3" name="Horse" />
</dataset>

Done with fixture. So far so good. Let's write tests. Please take a look at @JpaEntityManagerFactory annotation. You can use it to define which Persistence Unit you would like to use within your tests.


@DataSet("TagManagerTest.xml")
@JpaEntityManagerFactory(persistenceUnit = "testPersistenceUnit")
public class TagManagerTest extends UnitilsTestNG {
    @TestedObject
    TagManagerBean tagManager;

    @InjectIntoByType
    @PersistenceContext
    EntityManager entityManager;

    @Test
    public void getPersistedTagTestForNewTag() {
        // There is no newTag "Mouse" in the DB, so we expect that
        // it will be created and persisted
        Tag newTag = tagManager.findOrPersistTag("Mouse");

        assert newTag.getName().equals("Mouse");
        assert findTag("Mouse") != null;
    }

    @Test
    public void getPersistedTagTestForExistingTag() {
        // Get it manually from the DB and compare with a result of the tested method
        Tag existingTag = findTag("Apple");
        Tag tag = tagManager.findOrPersistTag("Apple");

        assert existingTag.equals(tag);
    }

    @Test
    public void getDistinctTagsNamesListTest(){
        List<String> result = tagManager.getDistinctTagsNamesList("Horse, Apple, Mouse");

        // Unitils provides some extremely useful methods like this
        ReflectionAssert.assertReflectionEquals(Arrays.asList("Horse", "Apple", "Mouse"), result);
    }


    @Test
    public void getPersistedTagsTest() {
        List<Tag> tags = tagManager.findOrPersistTags("Horse, Apple, Mouse, Dog, Orange");

        // Expecting that Mouse and Orange are became persisted
        assert findTag("Mouse") != null;
        assert findTag("Orange") != null;

        // Checks equality of field "name" of each Tag with provided values
        ReflectionAssert.assertPropertyLenientEquals("name", Arrays.asList("Horse", "Apple", "Mouse", "Dog", "Orange"), tags);
    }

    private Tag findTag(String name) {
        try {
            return (Tag) entityManager
              .createQuery("select t from Tag t where t.name = :name")
              .setParameter("name", name)
              .getSingleResult();
        } catch (NoResultException e) {
            return null;
        }
    }
}

Now let’s test CreatePostBean class.
The fixture (UploadPicture.xml):


<?xml version='1.0' encoding='UTF-8'?>
<dataset>
    <tag id="1" name="Apple" />
    <tag id="2" name="Dog" />
    <tag id="3" name="Horse" />
    <tag id="4" name="Cat" />
    <tag id="5" name="Bird" />
</dataset>

And the test class:


@DataSet("CreatePostTest.xml")
@JpaEntityManagerFactory(persistenceUnit = "testPersistenceUnit")
public class CreatePostTest extends UnitilsTestNG {
    @TestedObject
    CreatePostBean createPost;

    @InjectIntoByType
    @PersistenceContext
    EntityManager entityManager;

    @Mock
    @InjectIntoByType
    TagManagerBean tagManager;


    @Test
    public void createTest() {
        // Prepare state for testing
        String tagsNames = "Horse, Apple, Cat, Dog, Bird";
        String title = "Test title";
        String content = "Test content";

        // Prepare data for tagManager mock to return
        List<Tag> tagsListForMocking = (List<Tag>) entityManager.createQuery("select t from Tag t").getResultList();

        // Set expectations
        EasyMock
          .expect(tagManager.findOrPersistTags(tagsNames))
          .andReturn(tagsListForMocking);

        // Set replay mode and execute the code
        EasyMockUnitils.replay();

        createPost.create(title, content, tagsNames);

        // Done! Let's check what's happened

        Post post = (Post) entityManager.createQuery("select p from Post p").getSingleResult();

        assert post.getTitle().equals(title);
        assert post.getContent().equals(content);

        ReflectionAssert.assertPropertyLenientEquals("name", Arrays.asList("Horse", "Apple", "Cat", "Dog", "Bird"), post.getTags());

        // If you are familiar with EasyMock you notice that there's no invocation of verify() method to check
        // expectations for our mock. Thanks to Unitils -- it's invoked automatically.
    }
}    

That's all for today. You can download the project here. Please feel free to contact me if you have any questions.

Read more...

Friday, August 7, 2009

Solution for: «java.lang.VerifyError: (class: ..., method: toString signature: ()Ljava/lang/String;) Inconsistent stack height 1 != 0»

Here you can read about this problem in details: topic The solution is just place aop.xml in your META-INF directory.
<?xml version="1.0"?>
<aspectj>
    <weaver>
        <exclude within="*..*CGLIB*" />
    </weaver>

    <aspects>
        <aspect name="org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect"/>
        <aspect name="org.springframework.transaction.aspectj.AnnotationTransactionAspect"/>
    </aspects>
</aspectj>
Read more...

Wednesday, July 15, 2009

Solution for SpringSource dm Server startup problem: java.io.FileNotFoundException for jmxremote.access

Last night I tested new version of SpringSource dm server (2.0.0.M3). During startup I had a problem: server died with exception «Error: Exception thrown by the agent : java.io.FileNotFoundException: C:\dm\bin\..\config\management\jmxremote.access».

The solution is to give right permissions to jmxremote.access and jmxremote.password files. How to do it: http://java.sun.com/javase/6/docs/technotes/guides/management/security-windows.html

Hope it helps :)

Read more...

Saturday, June 27, 2009

"SMTP Error: Could not connect to SMTP host." problem solution for PHPMailer and GMail

Familiar with this problem?
Yesterday one of my clients asked me to help him with sending emails in PHP. In the internet there are many places where you can find step by step guides about how to do it, but in the most of them there are no mentions about OpenSSL. OpenSSL must be installed and OpenSSL extension must be enabled in php.ini for using PHPMailer with GMail via SSL.

That was the problem in my case.

The easiest way to check it is to invoke phpinfo(); and to make sure that "OpenSSL support" parameter with value "enabled" is presented. If the parameter is not exist try to uncomment string "extension=php_openssl.dll" in your php.ini. After that if you get an error while starting your web-server you should install OpenSSL.

P.S. PHP is not my main competency, but I hope this post will help you not to spend hours looking for a solution of the problem.

Read more...

Friday, April 3, 2009

Architecture solutions: polymorphism basics and advanced inheritance with Hibernate

This is the first post in architecture solutions series. In this series I'm going to talk about different architecture solutions used in my projects that I think are good enough to describe and re-use.

Problem

We need to develop a simple forum engine. Registered users after authentication can create topics and write posts. Authors can edit their posts within 15 minutes after publication.

Anonymous users can only write posts. They can't edit their post afterwards. Also while writing a post they must fill in 2 additional fields: nickname and CAPTCHA. Next time the nickname field is shown, it’s filled with the data entered when making a previous post. CAPTCHA is entered only once and later the field is not showed. Registration form behaves exactly the same.

Thoughts

Architecture for this system can be developed in different ways, but some of them look not very smart. For example, we can create 2 entities: Account (persistent entity for registered users) and Post. This way Post has two fields: Account author (reference to the Account object) and String anonymousAuthorNickname. When a post is made by an anonymous user, we store his nickname in anonymousAuthorNickname field. Otherwise, when post is made by a registered user, we can leave the anonymousAuthorNickname field empty and store a link to the author’s Account entity in the Account author field.

For the implementation of this architecture we can see different problems:

  1. During post creation or display we have to make a check whether this post is created by anonymous or registered user, because it determines the way author’s data is stored in the object, the logic of display and authorization.
  2. If we use Hibernate validators we have to duplicate the validator on Account's nickname field and Post's anonymousAuthorNickname field.
  3. Where should we store information about CAPTCHA and anonymous login (if entered)? Should we store them in the session?

Looks like too much trouble to use in a real-world situation. :)

Let's try another way which looks better: we can persist all users both registered and anonymous. But we have a new problem: the real lifetime of anonymous users’ accounts is limited to a session. Persisting hundreds of anonymous accounts only because it looks more convenient... hmm... not smart on my opinion. By the way we also should use inheritance to separate registered users' data (password, email, etc) and anonymous users’ data (is CAPTCHA entered, etc).

Is there a better way? The truth is out there ;)

I see the third way which doesn't have the disadvantages of the previous two.

Solution

I see two categories of users:

  1. Registered. Information about users from this category should be persisted, because it can be restored between sessions.
  2. Anonymous. Information about these users lives only during current session and the best way to store it is to put it in the session.

At the same time I see 2 categories of posts:

  1. Posts by registered authors. These posts have links to their authors.
  2. Posts by anonymous authors. These posts don't have links to authors, but have anonymousAuthorNickname field.

As we can see there are two hierarchies of inheritance. Use of inheritance gives us an ability to use polymorphism ... and the easiest solution to described problems.

Looks like magic! Ok. What do we do exactly?

We have an Account instance in the session. This instance could be the instance of subclass RegisteredAccount or subclass AnonymousAccount.

Suddenly user decides to make a post. It means that we invoke method Post loggedInAccount.getNewPost() and receive an instance of Post which could be the instance of either RegisteredAuthorPost or AnonymousAuthorPost. This Post instance is already initialized with actual data depending on current Account instance.

What should we do when a user tries to see posts in a topic? We should simply make a query to the database which returns all posts for requested topic.

How do we understand if user can edit the post? It is as simple as the post creation! We should invoke Boolean post.canBeEdited(loggedInAccount). The post makes a decision by itself if current account is allowed to edit it.

Now let's imagine what it would have looked like without polymorphism. Nightmare!

Now, how it looks in practice.

The first hierarchy.


@MappedSuperclass
public abstract class Account {
    private String nickname;

    @NotEmpty(message = "#{messages['account.error.nickname.empty']}")
    @Length(min = 2, max = 40, message = "#{messages['account.error.nickname.length']}")
    public String getNickname() {
        return nickname;
    }

    public void setNickname(String nickname) {
        this.nickname = nickname;
    }

    @Transient
    public abstract Post getNewPost();
}

public class AnonymousAccount extends Account {
    private Boolean captchaEntered;

    public Post getNewPost() {
        AnonymousAuthorPost newPost = new AnonymousAuthorPost();
        newPost.setAuthorNickname(getNickname());
        return newPost;
    }

    public boolean isCaptchaEntered() {
        return captchaEntered;
    }

    public void setCaptchaEntered (Boolean entered) {
        this.captchaEntered = entered;
    }
}

@Entity
public class RegisteredAccount extends Account {
    private Long id;
    private Date creationDate = new Date();
    private String password;
    private String email;

    @Id
    @GeneratedValue
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Date getCreationDate() {
        return creationDate;
    }

    public void setCreationDate(Date creationDate) {
        this.creationDate = creationDate;
    }

    @Email(message = "#{messages['post.error.mail.format']}")
    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @NotEmpty(message = "#{messages['account.error.password.empty']}")
    @Length(min = 6, max = 40, message = "#{messages['account.error.password.length']}")
    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Transient
    public Post getNewPost() {
        RegisteredAuthorPost newPost = new RegisteredAuthorPost();
        newPost.setAuthor(this);
        return newPost;
    }
}

As you can see only RegisteredAccount has @Entity annotation and only this entity is persisted. AnonymousAccount lives while session lives.

Also both types of account know what kind of Post they should create.

The second hierarchy.


@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(
    name="author_type",
    discriminatorType=DiscriminatorType.STRING
)
@DiscriminatorValue("unknown")
public abstract class Post {
    private Long id;
    private String body;
    private Topic topic;
    private Date creationDate = new Date();
    private Date deletionDate;
    private Status status = Status.ACTIVE;

    @Id
    @GeneratedValue
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    @NotNull
    @Length(min=1, max=4000, message = "#{messages['post.error.body.length']}")
    public String getBody() {
        return body;
    }

    public void setBody(String body) {
        this.body = body;
    }

    @ManyToOne
    public Topic getTopic() {
        return topic;
    }

    public void setTopic(Topic topic) {
        this.topic = topic;
    }

    @NotNull
    public Date getCreationDate() {
        return creationDate;
    }

    public void setCreationDate(Date creationDate) {
        this.creationDate = creationDate;
    }

    @NotNull
    @Enumerated(EnumType.STRING)
    public Status getStatus() {
        return status;
    }

    public void setStatus(Status status) {
        this.status = status;
    }

    public abstract String getAuthorNickname();
    public abstract void setAuthorNickname(String authorNickname);

    @Transient
    public abstract boolean canBeEdited(Account usingAccount);
}

@Entity
@DiscriminatorValue("anonymous")
@AttributeOverride(name = "authorNickname", column = @Column(name="anonymousAuthorNickname"))
public class AnonymousAuthorPost extends Post {
    String authorNickname;

    @Transient
    public String getDisplayingStyleClass() {
        return Messages.instance().get("anonymous-author-post-style-class");        
    }

    @Length(max = 50, message = "#{messages['account.error.nickname.length']}")
    public String getAuthorNickname() {
        return authorNickname;
    }

    public void setAuthorNickname(String authorNickname) {
        this.authorNickname = authorNickname;
    }

    @Transient
    public boolean canBeEdited(Account usedAccount) {
        return false;
    }
}

@Entity
@DiscriminatorValue("registered")
public class RegisteredAuthorPost extends Post {
    RegisteredAccount author;

    @NotNull
    @ManyToOne
    public RegisteredAccount getAuthor() {
        return author;
    }

    public void setAuthor(RegisteredAccount author) {
        this.author = author;
    }

    @Transient
    public String getAuthorNickname() {
        return getAuthor().getNickname();
    }

    @Transient
    public void setAuthorNickname(String authorNickname) {
       //nothing to do
    }

    @Transient
    private boolean isEditTimeElapsed() {
        …
        //check time here
    }

    @Transient
    public boolean canBeEdited(Account usedAccount) {
        if (usedAccount instanceof AnonymousAccount) return false;
   
        if (getAuthor().equals(usedAccount) && !isEditTimeElapsed()) return true;
        return false;
    }
}

Posts can be created both by registered and anonymous users, so we have two subclasses. Polymorphism gives us an ability to get nickname either from String field (for anonymous author) or from linked account object.

Conclusion

Architecture of this example is rather simple, but it shows how we can successfully use such rare used features of Hibernate as inheritance. Also this example demonstrates that mapping can be successfully used even for only one subclass of some unmapped abstract class.

Also you can see how to use persistence with inherited entities. Here we use one table mode with discriminator field and non-trivial usage of polymorphism: for one inherited entity methods are real getters-setters, but for the other one those methods are defined as @Transient and are used only to access linked object’s data.

Read more...

Tuesday, March 31, 2009

Java Mock Frameworks Comparison

In this post I try to tell you what mock frameworks are and what features they provide, and compare existing frameworks.

What is mock?

Let’s look at the example.

As we can see on the diagram Class A depends on Class B and Class C. Class B depends on Class D and Class E.

Ok. What should we do for unit testing of Class A? First of all we should isolate Class A. We should provide for instance of Class A something looks like instances of Class B and Class C, but which give us an opportunity to check behavior of testing instance.

These replacements are called mocks. Simple mocks which can only react like replacement classes with some canned answers to invocations made during tests are called stubs.

The diagram for unit testing of Class A:

Mock frameworks

Mock frameworks are the frameworks that give us an easy way to create mocks. Usually working with mock frameworks includes the following steps:
  1. Creation of a mock. Usually it looks like this (in EasyMock):
    ClassB mock = createMock(ClassB.class);
  2. Definition of the stubbed methods (what the method should do when a call happens). Sometimes definition is combined with expectations. EasyMock example:
    expect(mock.go()).andThrow(new RuntimeException());
  3. Definition of the expectations (how many times this method will be called, etc). EasyMock example:
    expectLastCall().times(3);
  4. Execution of the test code.
  5. Verification of the expectations. EasyMock example:
    verify(mock);

Different frameworks provide their own ways to define the expectations and a variety of features to check the tested object’s behavior.

Features

Let’s make a quick overview of common features provided by mock frameworks.

Value returning for stubbed method

It’s the ability of stubbed method to return value when invocation happens.

Mockito example:

when(mock.isDone()).thenReturn(true);

Exception throwing for stubbed method

It’s the ability of stubbed method to throw an exception. Mockito example:

when(mock.do()).thenThrow(new CantDoException());

Invocations count check

It’s the ability to check count of mock’s method invocations.

EasyMock example:

expect(mock.run()).times(1, 3); // expecting at least one and maximum three invocations

Method arguments check

It’s the ability to validate parameters passed to mock’s method. It could be range check, type check, etc. jMock example:

allowing(calculatorMock).sqrt(with(lessThan(0)); will(throwException(new IllegalArgumentException());

Invocations order for one mock check

It’s the ability to check the order of invocations for one mock. For example, in EasyMock we should create StrictMock with createStrictMock() method. StrictMock will check invocation order automatically.

Iterator-style stubbing

It’s the ability of a stubbed method to return different values for each invocation. Mockito example:

when(mock.getWeekday("My event")).thenReturn("Monday", "Tuesday", "Thursday");

Real objects spy

It’s the ability of a mock-object to act like proxy. It checks the invocations and redirect them to the real object. This feature can be useful for legacy code testing.

Mockito example from documentation:


List list = new LinkedList();
List spy = spy(list);

//optionally, you can stub out some methods:
when(spy.size()).thenReturn(100);
//using the spy calls real methods
spy.add("one");
spy.add("two");

Callback invocation from stubbed method

It’s the ability to invoke custom code from a stubbed method. Mockito documentation example:


when(mock.someMethod(anyString())).thenAnswer(new Answer() {
Object answer(InvocationOnMock invocation) {
        Object[] args = invocation.getArguments();
        Object mock = invocation.getMock();
        return "called with arguments: " + args;
    }
});

Mocking of final classes, methods, static and private fields

This ability could be useful for legacy code testing.

Stubbing of equals() and hashcode() methods

Most of frameworks (if not all) redefine these methods for their own needs. So it’s the usual limitation.

Thread safe

It’s the ability to run test with mock objects in multiple threads, so the mock objects are not shared between threads.

Invocation order between mocks check

It’s the ability to check the order of invocations between several mocks. For EasyMock it can be reached using control object:

IMocksControl control= createStrictControl();
IMyInterface mock1 = control.createMock(IMyInterface.class);
IMyInterface mock2 = control.createMock(IMyInterface.class);

Then framework will remember invocation between these mocks.

Java Mock Frameworks Features Comparison

First of all, please notice that all information about frameworks was taken from their documentation and I can’t guarantee that it is 100% accurate. If you have found any mistakes please feel free to contact me.

jMock EasyMock Mockito SevenMock JMockit rMock Unitils
Actual version 2.6-RC1 (7 Dec 2008) 2.4 (30 Aug 2008) 1.7 (24 Jan 2009) 2.1.0 (17 Jun 2008) 0.94 (30 Jan 2008) 2.0.0 (18 Mar 2007) 2.2 (23 Dec 2008)
Website http://jmock.org http://easymock.org http://code.google.com/p/mockito http://seven-mock.sourceforge.net https://jmockit.dev.java.net http://rmock.sourceforge.net http://www.unitils.org
Features Specification-like definition of mocks’ methods behavior (looks like DSL). «Record/Replay/Verify» model. Basic expectations are defined via calling appropriate mocks’ methods with actual data. Other types of expectations are defined with framework’s methods. «Verify after run» model. Basic expectations are checked after calling (mocks remember their methods invocations). Other types of expectations are defined as rules before running. Method stubbing and expectations are defined using inner classes. Methods stubbing are made using inner classes. Annotations for those methods define basic expectations. Other expectations are defined using DSL-like style. «Record/Replay/Verify» model. Expectations are defined using helper methods. Mockito-like «Verify after run» model.
Value returning for stubbed method + + + +* + + +
Exception throwing for stubbed method + + + +* + + +
Invocations count check + + + -* + + +*
Method arguments check + + + -* + + +
Invocations order for one mock check + + + + - + +
Iterator-style stubbing + + + -* +* - +
Real objects spy - - + - - + -
Callback invocation from stubbed method + + + - - - +
Mocking of final classes, methods, static and private fields - - - - + - -
Mocking of equals() and hashcode() methods - - - -
Thread safe - + + -
Invocation order between mocks check + + + + - + -
Total score 6.7 7.5 8.3 3.5 4.8 5.8 5.6

* — feature can be implemented, but not supported directly by a framework

Syntax comparison

Framework review would be incomplete with features comparison alone. Tests should be easy to read, so syntax is a very important criterion. That’s why I want to demonstrate testing of some example code with these frameworks.

I like the example from EasyMock documentation, so I rewrite it for other frameworks using their documentation as a reference. Let’s assume we have a DocumentManager object which references to Collaborator obects. DocumentManager has

void addDocument(String document)
method. When this method is executed DocumentManager (like Event Source in Observer design pattern) notifies its Collaborators with
void documentAdded(String document)
method. Also DocumentManager has
Boolean removeDocument(String document)
method which inquires its Collaborators with
Integer voteForRemoval(String document)
method. If the sum of votes is larger than zero, DocumentManager notifies its Collaborators about document removal with method
void documentRemoved(String document)
then returns true.

It can look like this:


public class DocumentManager() {
List collaborators = new ArrayList();

    ...

    public void addDocument(String document) {
        ...

        for (Collaborator collaborator : collaborators) collaborator.documentAdded(document);
    }


    public boolean removeDocument(String document) {
        Integer votingResult = 0;
        for (Collaborator collaborator : collaborators) {
          votingResult += collaborator.voteForRemoval(document);
        }


        if (votingResult > 0) {
            ...

          for (Collaborator collaborator : collaborators) collaborator.documentRemoved(document);
          return true;
        }
    }
}

In following examples I avoid the setup phase and concentrate directly on testing. Check it out:

EasyMock


collaboratorMock.documentAdded("Document");
expect(collaboratorMock.voteForRemoval("Document")).andReturn(42);
collaboratorMock.documentRemoved("Document");

replay(collaboratorMock);

documentManager.addDocument("Document");
assertTrue(documentManager.removeDocument("Document"));

verify(collaboratorMock);

jMock

context.checking(new Expectations() {{
oneOf(collaboratorMock).documentAdded("Document");
oneOf(collaboratorMock).voteForRemoval("Document"); will(returnValue(42));
oneOf(collaboratorMock).documentRemoved("Document");
}});

documentManager.addDocument("Document");
assertTrue(documentManager.removeDocument("Document"));

context.assertIsSatisfied();

Mockito


when(collaboratorMock.voteForRemoval("Document")).thenReturn(42);

documentManager.addDocument("Document");
assertTrue(documentManager.removeDocument("Document"));

verify(collaboratorMock).documentAdded("Document");
verify(collaboratorMock).voteForRemoval("Document");
verify(collaboratorMock).documentRemoved("Document");

SevenMock

mockControl.expect(new Collaborator() {

    public void documentAdded(String document) {
        assertEquals("Document", document);
    }

    public byte voteForRemoval(String document) {
        assertEquals("Document", document);
        return 42;
    }

    public void documentRemoved(String document) {
        assertEquals("Document", document);
    }
});

documentManager.addDocument("Document");
assertTrue(documentManager.removeDocument("Document"));

mockControl.verify();

JMockit

public void testDoOperationAbc() {
    Mockit.setUpMocks(CollaboratorMock.class);

    documentManager.addDocument("Document");
    assertTrue(documentManager.removeDocument("Document"));
}


@MockClass(realClass = Collaborator.class)
public static class CollaboratorMock {
    @Mock(invocations = 1)
    public void documentAdded(String document) {
        assertEquals("Document", document);
    }

    @Mock(invocations = 1)
    public byte voteForRemoval(String document) {
        assertEquals("Document", document);
        return 42;
    }

    @Mock(invocations = 1)
    public void documentRemoved(String document) {
        assertEquals("Document", document);
    }
}

rMock

collaboratorMock.documentAdded("Document");
collaboratorMock.voteForRemoval("Document");
modify().returnValue(42);
collaboratorMock.documentRemoved("Document");

startVerification();

documentManager.addDocument("Document");
assertTrue(documentManager.removeDocument("Document"));

Unitils

collaboratorMock.returns(42).voteForRemoval("Document");

documentManager.addDocument("Document");
assertTrue(documentManager.removeDocument("Document"));

collaboratorMock.assertInvoked().documentAdded("Document");
collaboratorMock.assertInvoked().documentRemoved("Document");

Conclusion

In my opinion EasyMock and Mockito are the most easy-to-use and feature-rich frameworks. As for me I would use one of these frameworks. Syntax is quite simple and easy to read.

JMockit is also rather promising framework made with instruments exposed by Java 5 SE JVM and provides mocking of static fields, final classes, etc. It can be quite useful for legacy code testing.

jMock is well-know framework, but in my opinion it has cumbersome syntax and doesn’t provide any additional features to compete with EasyMock or Mockit.

Unitils is more than just Mock framework. It provides different tools to organize your testing environment including mocking, JTA/Hibernate/DataSource support with DBUnit integration, assertion utils, annotation-driven mocks creation and injection, Spring integration and other useful tools. As I said it has its own mock framework which is quite simple and provides the most useful features. On my opinion only using of other Unitils features proves usage of its mock framework. By the way, it also supports EasyMock as mocking module.

rMock and SevenMock – «Neither fish nor fowl».

Read more...