Java Testing Journey (JUnit, Mockito, Spring Test, DBUnit)

I’ve been asked how to write the Java tests recently, then I decided to demonstrate all the popular testing tools in Java world by going through a very simple web application. Let’s start the journey now!

Prerequisite:

I am using Eclipse 4.3 and Tomcat to run all the code, so make sure you have them already. Besides I am using Github to host all my demo codes, though you may need a little knowledge about how to use git. The code is a Maven project, so be sure you know the basic about it.

Eclipse Configuration:

Set up the Encoding

Preferences -> General -> Workspace -> Text file encoding [other: UTF-8]

Not everyone in the world programs in English. Setting up a UTF-8 encoding makes sure others see your works.

Disable tab

Preferences -> General -> Editors -> Text Editors -> Insert spaces for tabs

Each editor displays the tab in different widths, but they all display the space in the same way. Always use white spaces instead of tabs in your code.

Set up the formatter

Preferences -> Java -> Code Styles -> Formatter -> Edit:Profile -> Indentation[Tab policy: Spaces only, Indentation size: 2(recommended), Tab size: 2(recommended)]

Remember to share the same format setting with all your develop team members. The same code styles provide a better readability.

Active save actions

Preferences -> Java -> Editor -> Save Actions -> ✓[Format source code, Organize imports]

Let Eclipse keep your code nice and clean every time you save the code.

Set up the static import lookup

Preferences -> Java -> Editor -> Content Assist -> Favorites -> New Type

Add following Types:

com.google.code.beanmatchers.BeanMatchers
com.google.common.base.Preconditions
com.google.common.base.Strings
com.google.common.collect.Lists
com.google.common.collect.Maps
com.google.common.collect.Sets
java.util.Collections
net.sf.rubycollect4j.RubyCollections
org.apache.commons.lang.StringUtils
org.mockito.Machers
org.mockito.Mockito
org.springframework.test.web.servlet.request.MockMvcRequestBuilders
org.springframework.test.web.servlet.result.MockMvcResultHandlers
org.springframework.test.web.servlet.result.MockMvcResultMatchers
org.springframework.test.web.servlet.setup.MockMvcBuilders

Modern Java uses lots of static imports to increase the readabilities of codes. Set them properly, otherwise Eclipse won’t find them for you.

Install EclEmma

Help -> Eclipse Marketplace -> Search[EclEmma] -> Install

EclEmma is a useful tool which shows you the code coverage after the execution of your application. After the installation, there is a icon which is like the run icon with a red-green bar under itcoverage-icon displayed in your Eclipse tool bar.

Demo Code

First, you need to clone the git repo.

git clone https://github.com/wnameless/java-testing-journey

There are 16 branches including master and step-1 ~ step-15 within this repo. I will go through this repo step by step.
Use following commands to switch between branches:

git checkout -f step-1
...
git checkout -f step-15

Step 1 – interface & generic

git checkout -f step-1

We are gonna build up a small bank application. This bank only keeps the information of accounts and account owners. Let’s design the interfaces of Owner and Account.

Owner.java

public interface Owner {
  public String getFirstName();
  public String getLastName();
  public String getSsn();
  public String getEmail();
  public String getPhone();
}

It’s a demo app, though don’t make it too complicated.

Account.java

public interface Account {
  public int getAccountNumber();
  public int getRoutingNumber();
  public List<? extends Owner> getOwners();
}

Remember to use the bounded wildcard(<? extends Owner>) to increase the flexibility of your API. If you don’t use the wildcard here, you won’t able to return List<OwnerImpl> in your later implementation.

pom.xml – dependencies

<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.11</version>
  <scope>test</scope>
</dependency>

JUnit is already in your pom.xml. If you don’t know how to use it, it’s fine. We will go through this later.

Step 2 – precondition & validation

git checkout -f step-2

We are going to create a validation utility class to validate all the future implementations of Owner and Account.

Q: We don’t have any implementation yet!
A: This is fine. Java is a OOP language. We don’t need the implantation details to do things.

Q: What are we going to validate?
A: Name, email, phone…, they all can be validated. Frankly speaking, the things you want to validate are much like the things you want to test for. Instead of wringing the unit testing immediately, we can do some warm ups with this validation class.

Q: Why we just start a new implementation and keep the validation in it?
A: Because it’s not reusable. We may have 10 kinds of implementations in the future.

New dependencies:

<dependency>
  <groupId>com.google.guava</groupId>
  <artifactId>guava</artifactId>
  <version>15.0</version>
</dependency>

Guava provides nice [checkNotNull, checkArgument, checkState] static methods to enforce preconditions.
PS: Guava also provides useful [newArrayList, newHashMap, newHashSet].
Precondition is important, because you don’t want your objects in wrong states. It’s good to find a bug with a test, but it’s even better to prevent a bug with preconditions.

<dependency>
  <groupId>commons-lang</groupId>
  <artifactId>commons-lang</artifactId>
  <version>2.6</version>
</dependency>

Commoms-lang provides the isBlank static method.

<dependency>
  <groupId>commons-validator</groupId>
  <artifactId>commons-validator</artifactId>
  <version>1.4.0</version>
</dependency>

It provides the EmailValidator.

<dependency>
  <groupId>com.googlecode.libphonenumber</groupId>
  <artifactId>libphonenumber</artifactId>
  <version>5.9</version>
</dependency>

It provides the PhoneNumberUtil.

BankValidator.java

public final class BankValidator {

  private static EmailValidator emailValidator = EmailValidator.getInstance();
  private static PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();

  private BankValidator() {}

  public static <T extends Owner> T validate(T owner) {
    ...
  }

  public static <T extends Account> T validate(T account) {
    ...
  }

  public static boolean tryValidate(Owner owner) {
    ...
  }

  public static boolean tryValidate(Account account) {
    ...
  }

}

The normal validate methods raise exceptions if any invalid property found.
The tryValidate methods return false even if invalid properties found.

public static <T extends Owner> T validate(T owner) {
  checkNotNull(owner, "Owner can't be null.");
  checkState(!isBlank(owner.getFirstName()), "First name can't be blank.");
  checkState(!isBlank(owner.getLastName()), "Last name can't be blank.");
  checkState(!isBlank(owner.getSsn()), "SSN can't be blank.");
  Pattern ssnRegEx = Pattern.compile("^\\d{3}[- ]?\\d{2,3}[- ]?\\d{4}$");
  checkState(ssnRegEx.matcher(owner.getSsn()).find(), "Invalid SSN.");

  if (!isNullOrEmpty(owner.getEmail()))
    checkState(emailValidator.isValid(owner.getEmail()), "Invalid email.");

  if (!isNullOrEmpty(owner.getPhone())) {
    boolean isValid = false;
    try {
      isValid =
          phoneUtil.isValidNumber(phoneUtil.parse(owner.getPhone(), "US"));
    } catch (NumberParseException e) {}
    checkState(isValid, "Invalid phone.");
  }

  return owner;
}

Email and phone are hard to validate. Instead of creating a regular expression by your own, try to use some of the open source libraries for your needs.
Guava allows you to omit the exception messages but don’t! Providing detail infomation of your exceptions makes others easier to debug.

You can read the rest methods by your own now.

Step 3 – unit testing & mock

git checkout -f step-3

Finally we are going to write our first unit test. First, to make a package with a same name of the package where the BankValidator is put under src/test/java. By convention, we create our tests under the same package of our testing targets, but we don’t want our test codes to ship with our product. That’s why we put them under src/test/java instead of src/main/java.

New dependency:

<dependency>
  <groupId>org.mockito</groupId>
  <artifactId>mockito-core</artifactId>
  <version>1.9.5</version>
  <scope>test</scope>
</dependency>

Mockito is a powerful mock tool for Java. It’s very easy to use.

Remember, we don’t have any implementations yet, but we still need some objects to test our BankValidator, therefore we can mock objects for testing purposes.

Q: When do we need to mock?
A: When you only have the interfaces. When objects are too expensive(time/memory consuming…) to create. When some of the object return values are hard to produce. When it is better to do.

BankValidatorTest.java

public class BankValidatorTest {
  @Mock
  Owner owner;
  @Mock
  Account account;

  @Before
  public void setUp() throws Exception {
    MockitoAnnotations.initMocks(this);
    when(owner.getFirstName()).thenReturn("John");
    when(owner.getLastName()).thenReturn("Doe");
    when(owner.getSsn()).thenReturn("123-456-7890");
    when(owner.getEmail()).thenReturn(null);
    when(owner.getPhone()).thenReturn(null);
    when(account.getAccountNumber()).thenReturn(12345);
    when(account.getRoutingNumber()).thenReturn(67890);
    doReturn(newArrayList(owner)).when(account).getOwners();
  }

  @Test
  public void constructorShouldBePrivate() throws Exception {
    Constructor c = BankValidator.class.getDeclaredConstructor();
    assertTrue(Modifier.isPrivate(c.getModifiers()));
    c.setAccessible(true);
    c.newInstance();
  }

  @Test
  public void testValidateWithOwner() {
    assertSame(owner, BankValidator.validate(owner));
  }

  @Test(expected = NullPointerException.class)
  public void validateWithNullOwnerShouldRaiseException() {
    BankValidator.validate((Owner) null);
  }

  @Test(expected = IllegalStateException.class)
  public void ownerWithNullFirstNameIsInvalid() {
    when(owner.getFirstName()).thenReturn(null);
    BankValidator.validate(owner);
  }
  ...
}

A JUnit test class is just like a ordinary Java class, but with few annotations in it.

JUnit annotations:

@Test - Any method annotated with it is a test case.
@Before - Things to be done before each test case.

Eclipse has its JUnit runner. When you try to run a Java class with @Test inside it, Eclipse runs it with the JUnit runner. That’s why you don’t need a Java main method.

Mockito annotation:

@Mock - An object need to be mocked.

Q: What did @Mock do for us?
A: Nothing.
Any Java annotation is simply a marker/tag for Java compiler(compilation time) or JVM(runtime) to see. It does nothing by itself.
It is so powerful because it is so simple.
All the magics are performed by the runner who sees those annotations.
In this case, the magician is located at following line of code:

MockitoAnnotations.initMocks(this);

Q: What’s a mock object?
A: Every Java object gets its own method signatures which define the input/output values and types. Mockito simply mimics those signatures by taking any values of the input types and returning the default value of output types. For example, if getName() method returns a String, a mock getName() method returns null because null is the default value of String.

The behavior of a mock object can be override by following codes:

when(owner.getFirstName()).thenReturn("John");
doReturn(newArrayList(owner)).when(account).getOwners();

Modifier can be tested by Java reflection API.

Constructor c = BankValidator.class.getDeclaredConstructor();
assertTrue(Modifier.isPrivate(c.getModifiers()));

Basically, unit testing is done by calling a bunch of assertions to verify if the program runs correctly. You can find all assertions under org.junit.Assert. We are using assertTrue in this case.

Sometimes, we expect to have an exception. Here is a convenient approach to test it.

@Test(expected = NullPointerException.class)

If we don’t use this annotation, we may end up with a code something like this:

try{
  ...
  fail();
}catch(Exception e){}

You can go over rest test cases by your own now.
junit-result

EclEmma – code coverage
When you finish all the tests and run it, you will get a green bar(if everything passed) appeared on the bottom of your Eclipse. It’s great!

Q: How can I tell whether every piece of my codes has been tested?
A: Yes, you can tell it after you use the right tool.

Try to run your test class with the Coverage icon on your Eclipse tool bar. After it runs, you will discover that all your source codes are highlighted with either green, yellow or red color. You can now easily tell which part of your codes has been tested.
coverage-result

Step 4 – equals, hashCode & persistence API

git checkout -f step-4

We are preparing to build our little bank as a web application, so let’s implement some Java beans by the Owner and Account interfaces first.

New dependency:

<dependency>
  <groupId>javax.persistence</groupId>
  <artifactId>persistence-api</artifactId>
  <version>1.0.2</version>
</dependency>

Java persistence API provides a nice annotation-driven approach to map a Java bean into a database.

Account.java

@Entity
@Table(name = "ACCOUNT")
public class AccountBean implements Account {
  @Id
  @Column(name = "ID")
  @GeneratedValue
  private Integer id;

  @Column(name = "ACCOUNT_NUMBER", unique = true)
  private int accountNumber;

  @Column(name = "ROUTING_NUMBER")
  private int routingNumber;

  @ManyToMany(fetch = FetchType.EAGER)
  @JoinTable(name = "ACCOUNT_OWNER", joinColumns = { @JoinColumn(
      name = "ACCOUNT_ID", referencedColumnName = "ID") },
      inverseJoinColumns = { @JoinColumn(name = "OWNER_ID",
          referencedColumnName = "ID") })
  private List owners;

  ...(getters and setters)

  @Override
  public final boolean equals(Object o) {
    if (o instanceof Account) {
      Account account = (Account) o;
      return Objects.equal(accountNumber, account.getAccountNumber())
          && Objects.equal(routingNumber, account.getRoutingNumber())
          && Objects.equal(owners, account.getOwners());
    }
    return false;
  }

  @Override
  public final int hashCode() {
    return Objects.hashCode(accountNumber, routingNumber, owners);
  }

  @Override
  public String toString() {
    return Objects.toStringHelper(this).add("accountNumber", accountNumber)
        .add("routingNumber", routingNumber).add("owners", owners).toString();
  }
}

Persistence API annotation

@Entity
@Table(name = "ACCOUNT")
@Id
@GeneratedValue
@Column(name = "ACCOUNT_NUMBER", unique = true)

Those annotations are quite straight forward. They simply map the properties of a class into a database table.

Here are 2 sophisticated annotations:

@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "ACCOUNT_OWNER", joinColumns = { @JoinColumn(
    name = "ACCOUNT_ID", referencedColumnName = "ID") },
    inverseJoinColumns = { @JoinColumn(name = "OWNER_ID",
        referencedColumnName = "ID") })

There are 4 kinds of associations: @OneToOne, @OneToMany, @ManyToOne and @ManyToMany.
Relational database needs a join table to describe what’s the relation between any 2 database entries.
That’s why we need the @JoinTable annotation which tells what table and what columns represent those relations.
After @JoinTable is written, we don’t need to create another Java bean for the join table.

equals, hashCode and toString

@Override
public final boolean equals(Object o) {
  if (o instanceof Account) {
    Account account = (Account) o;
    return Objects.equal(accountNumber, account.getAccountNumber())
        && Objects.equal(routingNumber, account.getRoutingNumber())
        && Objects.equal(owners, account.getOwners());
  }
  return false;
}
@Override
public final int hashCode() {
  return Objects.hashCode(accountNumber, routingNumber, owners);
}
@Override
public String toString() {
  return Objects.toStringHelper(this).add("accountNumber", accountNumber)
      .add("routingNumber", routingNumber).add("owners", owners).toString();
}

You probably need to override these 3 methods every time you create a new class. It’s very necessary because bunch of the Java collections based on them, but it’s also very boring.
Thanks for Guava, it provides convenient [Objects.equal, Objects.hashCode, Objects.toStringHelper] methods to make things easier.

Q: Why there is no property id in any of those 3 override methods?
A: AccountBean implements Account interface. We assume it only contains 3 properties[accountNumber, routingNumber, owners]. If we add one more property id, the general contract betweens AccountBean and other Account implementations will be broken.

You can read the OwnerBean by yourself now.

Step 5 – testing bean

git checkout -f step-5

We just added 2 more classes to our project, therefore we need to test them as well.

New dependencies:

<dependency>
  <groupId>com.google.code.bean-matchers</groupId>
  <artifactId>bean-matchers</artifactId>
  <version>0.8.1</version>
  <scope>test</scope>
</dependency>

A simple Java bean usually contains lots of getters and setters which can’t be automatically generated by Eclipse(Source -> Generate Getters and Setters…).
If creating a Java bean is a boring task, then unit testing of a Java bean is way more boring.
However we still need to do it, but please do it in a smart way.

<dependency>
  <groupId>nl.jqno.equalsverifier</groupId>
  <artifactId>equalsverifier</artifactId>
  <version>1.4</version>
  <scope>test</scope>
</dependency>

Just as I said, we probably need to override the equals and hashCode at most of the time. We need a tool to test those methods for us.

OwnerBeanTest.java

public class OwnerBeanTest {
  @Test
  public void testBean() {
    assertThat(
        OwnerBean.class,
        allOf(hasValidBeanConstructor(), hasValidGettersAndSetters(),
            hasValidBeanToStringExcluding("id")));
  }
  @Test
  public void testEquaslToAndHashCode() {
    EqualsVerifier.forClass(OwnerBean.class).suppress(Warning.NONFINAL_FIELDS)
        .verify();
  }
}

Can you believe it? With the help of proper tools, unit testings can be easy.

The other test is simple as this one.

Step 6 – DAO

git checkout -f step-6

We now have our beans, but it’s not enough. We need Data Access Objects to persist those beans into databases and I choose Hibernate to be our ORM.
The DAO classes are look like the same, even though they all persist different kinds of beans. We don’t want to repeat our codes in all DAO classes, so we want do it in a much generic way.

New dependency:

<dependency>
  <groupId>com.googlecode.genericdao</groupId>
  <artifactId>dao-hibernate</artifactId>
  <version>1.1.0</version>
</dependency>

This lib provides a generic approach to implement DAOs.
Version 1.1.0 is for Hibernate 3. Version 1.2.0 is for Hibernate 4.

OwnerDAO

public interface OwnerDAO extends GenericDAO {}

AccountDAO

public interface AccountDAO extends GenericDAO {}

OwnerDAO

public class OwnerDAOImpl extends GenericDAOImpl implements
    OwnerDAO {}

AccountDAOImpl

public class AccountDAOImpl extends GenericDAOImpl
    implements AccountDAO {}

Can you believe that we just finished all of our DAOs?
If we don’t use dao-hibernate, we should write something like this over and over again:

protected Session getSession() {
  return HibernateUtil.getSession();
}

public void save(T entity) {
  getSession().saveOrUpdate(entity);
}

public void merge(T entity) {
  getSession().merge(entity);
}

public void delete(T entity) {
  getSession().delete(entity);
}
...

It’s not very happy to do, right? Always keep yourself DRY.

Step 7 – Hibernate testing with H2 database

git checkout -f step-7

Even though we are using a reliable 3rd party lib to implement our DAOs, it doesn’t mean we don’t need to test it.

New dependencies:

<dependency>
  <groupId>org.hibernate</groupId>
  <artifactId>hibernate-annotations</artifactId>
  <version>3.3.1.GA</version>
</dependency>

We are using annotations to describe our entity beans, therefore we need this lib for Hibernate to use.
The version 3.3.1.GA is used to match the Hibernate version of dao-hibernate 1.1.0.
If you are using dao-hibernate 1.2.0, please change it to 4.2.0.CR1.

<dependency>
  <groupId>javax.transaction</groupId>
  <artifactId>jta</artifactId>
  <version>1.1</version>
</dependency>

A dependency for hibernate-annotations.

<dependency>
  <groupId>com.h2database</groupId>
  <artifactId>h2</artifactId>
  <version>1.3.175</version>
</dependency>

We are using H2 database in this demo application. It has server, embedded and in-memory modes which makes it perfect to be used under development and testing environments.

<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-simple</artifactId>
  <version>1.7.6</version>
</dependency>

We need a logger implementation for hibernate-annotations to log. Beware of that slf4j-simple only redirect all logs to the console output. It’s good for development, but remember to change it in production.

Hibernate configuration file(src/test/resources/hibernate-test.cfg.xml)

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration SYSTEM 
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
  <session-factory>
    <property name="hibernate.dialect">org.hibernate.dialect.H2Dialect</property>
    <property name="hibernate.connection.driver_class">org.h2.Driver</property>
    <property name="hibernate.connection.url">jdbc:h2:mem:test</property>
    <property name="hibernate.connection.username">sa</property>
    <property name="hibernate.connection.password"></property>
    <property name="current_session_context_class">thread</property>
    <property name="hibernate.show_sql">true</property>
    <property name="hibernate.hbm2ddl.auto">create-drop</property>

    <mapping class="app.models.OwnerBean"></mapping>
    <mapping class="app.models.AccountBean"></mapping>
  </session-factory>
</hibernate-configuration>

hibernate.dialect – Because of the dialect, we can easily switch between databases. We decide to use H2 today, but we may change it to MySQL tomorrow.

hibernate.hbm2ddl.auto – It is the best part of Hibernate, it can auto generate the database schema based on the entity beans. The value create-drop is suitable for testing, but you probably want it to be [validate, update] in production.

<mapping> – Don’t forget to tell Hibernate where your models are.

OwnerDAOImplTest.java

public class OwnerDAOImplTest {
  OwnerDAOImpl dao = new OwnerDAOImpl();
  OwnerBean bean;
  SessionFactory sf;
  Session s;

  @Before
  public void setUp() throws Exception {
    bean = new OwnerBean();
    bean.setFirstName("John");
    bean.setLastName("Doe");
    bean.setSsn("123-456-7890");
    sf =
        new AnnotationConfiguration().configure("hibernate.cfg.xml")
            .buildSessionFactory();
    dao.setSessionFactory(sf);
    s = sf.getCurrentSession();
    s.beginTransaction();
  }

  @After
  public void tearDown() throws Exception {
    s.getTransaction().rollback();
  }

  @Test
  public void testSave() {
    assertTrue(dao.save(bean));
  }

  @Test
  public void testFindAll() {
    dao.save(bean);
    assertEquals(1, dao.findAll().size());
    assertEquals(bean, dao.findAll().get(0));
  }

  @Test(expected = ConstraintViolationException.class)
  public void duplicateSsnCanNotBeSaved() {
    dao.save(bean);
    bean = new OwnerBean();
    bean.setFirstName("Jane");
    bean.setLastName("Doe");
    bean.setSsn("123-456-7890");
    dao.save(bean);
  }
}

If you are using a reliable and well-tested lib, you are not going to test it again. We simply try to test if our data can be saved and retrieved successfully. Moreover, we want to test if our annotated constraint works.

Q: Why we need to do dao.save(bean) in both testSave() and testFindAll() method? Can we remove the dao.save(bean) in testFindAll()?
A: No, you can’t. Every test case is independent and must be independent. Try to imagine that you are using different databases to test each method. Most of all, JUnit won’t run your test cases by the order you gave in the test class.

new AnnotationConfiguration().configure("hibernate-test.cfg.xml")
            .buildSessionFactory()

This how we use a configuration file + annotations to build up a database session.

@Before
public void setUp() throws Exception {
  s = sf.getCurrentSession();
  s.beginTransaction();
}

@After
public void tearDown() throws Exception {
  s.getTransaction().rollback();
}

Thanks for JUnit @Before and @After callbacks, we can easily wrap every our test into a transaction. We want each test to be independent, therefore remember to rollback database after each test.

Too lazy to handle the transaction? Let’s try another test framework.

Step 8 – Hibernate testing with Spring

git checkout -f step-8

We are adding the Spring Framework to our demo application now.

New dependencies:

<dependency>
  <groupId>javax.inject</groupId>
  <artifactId>javax.inject</artifactId>
  <version>1</version>
</dependency>

Spring Framework highly depends on the concepts of Inversion of Control and Dependency Injection. If you used Spring before, you probably get familiar with annotations such as @Autowired, @Component, @Repository.
After JSR330 released, I recommend to use simply the @Named and @Inject to replace all the Spring-only annotations.

Add following property to your pom.xml first.

<properties>
  <spring.version>3.2.7.RELEASE</spring.version>
</properties>

We may not need them all for now, but let’s put them altogether:

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-web</artifactId>
  <version>${spring.version}</version>
  </dependency>
<dependency>
<groupId>org.springframework</groupId>
  <artifactId>spring-webmvc</artifactId>
  <version>${spring.version}</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-orm</artifactId>
  <version>${spring.version}</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
 <dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-test</artifactId>
  <version>${spring.version}</version>
  <scope>test</scope>
</dependency>

Spring Framework is one of the most popular web framework in the world of Java and it is well modularized. Even though you doesn’t want to build a web application, you can still have lots of benefits from it.

<dependency>
  <groupId>javax.servlet.jsp</groupId>
  <artifactId>jsp-api</artifactId>
  <version>2.1</version>
  <scope>provided</scope>
</dependency>
<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>servlet-api</artifactId>
  <version>2.5</version>
  <scope>provided</scope>
</dependency>

These 2 dependencies are often provided by the servlet containers such as Tomcat or Jetty. We add them for developing needs, but we don’t want them to ship with our final product and that’s why their scopes is restricted to provided.

<dependency>
  <groupId>commons-dbcp</groupId>
  <artifactId>commons-dbcp</artifactId>
  <version>1.4</version>
</dependency>

The dependency for Spring to build a datasource of the database.

Spring Configuration

JDBC properties(src/test/resources/jdbc.properties):

jdbc.driverClassName=org.h2.Driver
jdbc.dialect=org.hibernate.dialect.H2Dialect
jdbc.databaseurl=jdbc:h2:mem:test
jdbc.username=sa
jdbc.password=

A properties file of JDBC datasource.

Hibernate config(src/test/resources/hibernate.cfg.xml):

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration SYSTEM 
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
  <session-factory>
    <property name="hibernate.show_sql">true</property>
    <property name="hibernate.hbm2ddl.auto">create-drop</property>

    <mapping class="app.models.OwnerBean"></mapping>
    <mapping class="app.models.AccountBean"></mapping>
  </session-factory>
</hibernate-configuration>

Most of the settings are extracted to jdbc.properties. Here is the rest of them.

<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:context="http://www.springframework.org/schema/context"
  xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx"
  xsi:schemaLocation="

http://www.springframework.org/schema/beans


http://www.springframework.org/schema/beans/spring-beans-3.0.xsd


http://www.springframework.org/schema/context


http://www.springframework.org/schema/context/spring-context-3.0.xsd


http://www.springframework.org/schema/mvc


http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd


http://www.springframework.org/schema/tx

http://www.springframework.org/schema/tx/spring-tx.xsd">

  <context:component-scan base-package="app.controllers" />
  <context:component-scan base-package="app.models" />

  <mvc:annotation-driven />

  <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix">
      <value>/WEB-INF/classes/app/views/</value>
    </property>
    <property name="suffix">
      <value>.jsp</value>
    </property>
  </bean>

  <bean id="propertyConfigurer"
    class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
    p:location="classpath:jdbc.properties"></bean>

  <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
    destroy-method="close" p:driverClassName="${jdbc.driverClassName}"
    p:url="${jdbc.databaseurl}" p:username="${jdbc.username}" p:password="${jdbc.password}">
  </bean>

  <bean id="sessionFactory"
    class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource"></property>
    <property name="configLocation">
      <value>classpath:hibernate.cfg.xml</value>
    </property>
    <property name="configurationClass">
      <value>org.hibernate.cfg.AnnotationConfiguration</value>
    </property>
    <property name="hibernateProperties">
      <props>
        <prop key="hibernate.dialect">${jdbc.dialect}</prop>
      </props>
     </property>
  </bean>

  <tx:annotation-driven />
  <bean id="transactionManager"
    class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory"></property>
  </bean>

</beans>

This XML file is the most crucial part to use the Spring Framework. I mentioned before that Spring highly depends on dependency injection. Spring uses XML-based injection to inject all dependencies of a application at runtime. This file is where you define all the dependencies(beans). Visit Spring reference for more information.

Before we start to use Spring to run our tests, there is a problem for us to solve.
Q: The datasource and session factory are now handled by Spring. How can we pass those dependencies to Hibernate?
A: The answer is always the same one which is the dependency injection.

@Named
public class OwnerDAOImpl extends GenericDAOImpl<OwnerBean, Integer> implements
    OwnerDAO {

  @Inject
  @Override
  public void setSessionFactory(SessionFactory sessionFactory) {
    super.setSessionFactory(sessionFactory);
  }
}

@Named
public class AccountDAOImpl extends GenericDAOImpl<AccountBean, Integer>
    implements AccountDAO {

  @Inject
  @Override
  public void setSessionFactory(SessionFactory sessionFactory) {
    super.setSessionFactory(sessionFactory);
  }
}

The @Inject annotation can be used on constructor, setter and property, so let’s override the setSessionFactory for all DAOs with @Inject, than we are all set.
The @Named annotation is used to declare a dependency. Those 2 DAO implementations are exactly the dependencies for our test cases to run later, so let’s annotate them with @Named.

AccountDAOImplTest.java

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/context.xml" })
@TransactionConfiguration(defaultRollback = true)
@Transactional
public class AccountDAOImplTest {

  @Inject
  AccountDAO dao;
  OwnerBean owner;
  AccountBean account;

  @Before
  public void setUp() throws Exception {
    owner = new OwnerBean();
    owner.setFirstName("John");
    owner.setLastName("Doe");
    owner.setSsn("123-456-7890");
    account = new AccountBean();
    account.setAccountNumber(12345);
    account.setRoutingNumber(67890);
    account.setOwners(newArrayList(owner));
  }

  @Test
  public void testSave() { ... }

  @Test
  public void testFindAll() { ... }

  @Test
  public void accountOwnerShouldBeSaved() { ... }

  @Test(expected = ConstraintViolationException.class)
  public void duplicateAccountNumberCanNotBeSaved() { ... }
}

After all the hard work, we can now start to enjoy the pleasure Spring brings to us.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/context.xml" })

We can run our tests with Spring by adding those annotations.

@Inject
AccountDAO dao;

Spring injects dependencies for us, therefor we don’t need to manually instantiate them anymore.

@TransactionConfiguration(defaultRollback = true)
@Transactional

Remember how we set up the transaction at last step? All the works can now be replaced by these 2 annotations.

The rest parts of this test class are pretty easy. You can go over them by yourself.

Step 9 – service layer

git checkout -f step-9

A service is often called by all kinds of controllers to accomplish jobs in a MVC web application. Instead of providing controllers the permission to call DAOs directly, we add a service layer in between, therefore we can do more business logic within this layer. After all, we don’t like controllers to do many things, they are coordinators not workers.

New dependency:

<dependency>
  <groupId>net.sf.rubycollect4j</groupId>
  <artifactId>rubycollect4j</artifactId>
  <version>1.7.5</version>
</dependency>

Rubycollect4j was inspired by the programming language Ruby(I am also a Ruby lover). It provides numerous of friendly ruby-like methods to Java List and Map.

AccountService.java

public interface AccountService {
  public boolean addAccount(int accountNumber, int routingNumber,
      List<Integer> ownerIds);
  public List<AccountBean> getAllAccounts();
  public boolean deleteAccount(Integer accountId);
}

As you can see, we are starting to use the dependency injection more. You have to get use to start with interfaces before you actually implement anything. To simplify this demo, I don’t want this service to be too complicated.

AccountServiceImpl.java

@Named
public class AccountServiceImpl implements AccountService {
  @Inject
  private AccountDAO accountDAO;

  @Inject
  private OwnerDAO ownerDAO;

  @Transactional
  @Override
  public boolean addAccount(int accountNumber, int routingNumber,
      List ownerIds) {
    OwnerBean[] owners =
        ownerDAO.find(ownerIds.toArray(new Integer[ownerIds.size()]));
    AccountBean account = new AccountBean();
    account.setAccountNumber(accountNumber);
    account.setRoutingNumber(routingNumber);
    account.setOwners(newRubyArray(owners).compact().uniq());
    return accountDAO.save(BankValidator.validate(account));
  }

  @Transactional
  @Override
  public List getAllAccounts() {
    return accountDAO.findAll();
  }

  @Transactional
  @Override
  public boolean deleteAccount(Integer accountId) {
    return accountDAO.removeById(accountId);
  }
}

Don’t forget to add @Named annotation to this class. It will be a dependency for our application to run.

@Inject
private AccountDAO accountDAO;

@Inject
private OwnerDAO ownerDAO;

DAOs are injected at runtime. It is great because even if we change the implementation of DAOs in the future, we don’t need to change any line of codes here.

OwnerBean[] owners = ownerDAO.find(ownerIds.toArray(new Integer[ownerIds.size()]));
...
account.setOwners(newRubyArray(owners).compact().uniq());
return accountDAO.save(BankValidator.validate(account));

The owners returned by DAO may contains null objects. To avoid null, using newRubyArray to remove null and duplicated owners, therefore the validation of BankValidator could be much more meaningful.

@Transactional

The @Transactional annotation can be used any method which involved with database operation.

The OwnerServiceImpl.java is pretty much the same thing. Try to Read it by yourself.

Step 10 – testing service layer

git checkout -f step-10

Just like what we did before, we have to test all our codes.

There are absolutely no new stuffs in this step, so I would suggest you to take those 2 test cases(OwnerServiceImplTest.java, AccountServiceImplTest.java) as an excise.

However I would like to explain one of the test method quickly.

...
service.addOwner("Jane", "Doe", "098-765-4321", null, null);
assertEquals(2, dao.findAll().size());

Do you think which one is reasonable? The one above or the one below?

...
service.addOwner("Jane", "Doe", "098-765-4321", null, null);
assertEquals(2, service.findAll().size());

I think the first test is more reasonable, because services are based on DAOs and all DAOs have been tested(in step 8). To conclude, using a DAO to verify the result of a service is more logical.

Step 11 – MVC

git checkout -f step-11

We are turning our project into a web application now.

Add packaging target to your pom.xml.

<modelVersion>4.0.0</modelVersion>
<groupId>com.wmw</groupId>
<artifactId>java-testing-journey</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>

After you save the pom.xml, Eclipse should start to recompile the whole project.
When it’s done, a new webapp/WEB-INF folder is created under your src/main folder.

Copy src/test/resources/hibernate.cfg.xml to src/main/resources/hibernate.cfg.xml
Change the hibernate.hbm2ddl.auto property from create-drop to update:

<property name="hibernate.hbm2ddl.auto">update</property>

Copy src/test/resources/context.xml to src/main/webapp/WEB-INF/mvc-dispatcher-servlet.xml
Change the following bean from:

<bean id="propertyConfigurer"
  class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
  p:location="classpath:jdbc.properties"></bean>

to:

<bean id="propertyConfigurer"
  class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
  p:location="/WEB-INF/jdbc.properties"></bean>

You can still place your jdbc.properties under the classpath, but it’s not recommended. If you leave your configuration inside the war file, you have to recompile your project every time you redeploy to a new host.

JDBC properties(src/main/webapp/WEB-INF/jdbc.properties):

jdbc.driverClassName=org.h2.Driver
jdbc.dialect=org.hibernate.dialect.H2Dialect
jdbc.databaseurl=jdbc:h2:mem:bank
jdbc.username=sa
jdbc.password=

The reason I am still using the in-memory database is because it’s a demo application. You should change the database url to a embedded or server database in production environment.

web.xml(src/main/webapp/WEB-INF/web.xml):

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="http://java.sun.com/xml/ns/javaee"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
  id="WebApp_ID" version="2.5">

  <display-name>Java Testing Journey</display-name>

  <servlet>
     <servlet-name>mvc-dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>mvc-dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
  </context-param>

  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>

</web-app>

After all these configurations, we can add our home page now.

HomeController.java

@Controller
@RequestMapping("/")
public class HomeController {

  @RequestMapping(method = RequestMethod.GET)
  public String index(ModelMap model) {
    return "index";
  }

}

We are using the annotation-driven Spring MVC which makes the controller definition a simple task.

@Controller
@RequestMapping("/")

This 2 annotations imply every request under “/” are handle by this controller.

@RequestMapping(method = RequestMethod.GET)

It implies this method handles the GET “/” action.
Besides, there are 8 different request methods in HTTP.

ModelMap model

It’s simply a Map data structure. The things you put in here can be accessed by JSP pages in the views.

return "index";

Although it’s just a String, it would actually render your ModelMap with index.jsp.
It’s all defined in the mvc-dispatcher-servlet.xml:

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name="prefix">
    <value>/WEB-INF/classes/app/views/</value>
  </property>
  <property name="suffix">
    <value>.jsp</value>
  </property>
</bean>

index.jsp(app.views.index.jsp)

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Java Testing Journey</title>
</head>
<body>
	<h1>Hello!</h1>
</body>
</html>

Let’s say hello to the world.

After everything is done, run Tomcat with this project and open your browser to

http://localhost:8080/java-testing-journey/

You should now see the homepage with a big “Hello!”.

Step 12 – testing controller

git checkout -f step-12

We just created a simple home page, let’s test it.

HomeControllerTest

public class HomeControllerTest {
  MockMvc mockMvc;

  @InjectMocks
  HomeController controller;

  @Before
  public void setUp() throws Exception {
    MockitoAnnotations.initMocks(this);
    mockMvc = standaloneSetup(controller).build();
  }

  @Test
  public void getIndex() throws Exception {
    mockMvc.perform(get("/")).andExpect(status().isOk())
        .andExpect(view().name("index"));
  }
}

Do you still remember how to use Mockito? Let’s practice it again.

@InjectMocks
HomeController controller;

We all know that there are lots of dependencies within a Spring controller.
This annotation tells Mockito to mock all those dependencies for us.

MockitoAnnotations.initMocks(this);

Again, don’t forget the magic line.

mockMvc.perform(get("/")).andExpect(status().isOk())
    .andExpect(view().name("index"));

The Spring MockMVC provides tons of convenient static methods to allow you test your web application. Here is just a little example, we will see more later.

Step 13 – JSP views

git checkout -f step-13

We are going to create 2 webpages for our owner and account managements.

New dependency:

<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>jstl</artifactId>
  <version>1.2</version>
</dependency>

We need to use some JSTL tag in our views.

OwnersController.java

@Controller
@RequestMapping("/owners")
public class OwnersController {
  @Inject
  private OwnerService ownerService;

  @RequestMapping(method = GET)
  public String index(ModelMap model) {
    model.addAttribute("owners", ownerService.getAllOwners());
    return "owners/index";
  }

  @RequestMapping(method = POST)
  public String create(ModelMap model,//
      @RequestParam String firstName,//
      @RequestParam String lastName,//
      @RequestParam String ssn,//
      @RequestParam String email,//
      @RequestParam String phone) {

    ownerService.addOwner(firstName, lastName, ssn, email, phone);
    model.addAttribute("owners", ownerService.getAllOwners());
    return "owners/index";
  }
}

There are often 3 steps processed inside the method of a controller:
1. Call service with parameters.
2. Put necessary attributes in the ModelMap.
3. Render the page.
They are all very straight forward. Don’t let your controller deal with too much logics. Follow the skinny controller fat model principle.

owners/index.jsp(app.views.owners.index.jsp)

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
  pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Java Testing Journey</title>
</head>
<body>
  <h1>Owners</h1>
  <table>
    <thead>
      <tr>
        <th>Name</th>
        <th>SSN</th>
        <th>Email</th>
        <th>Phone</th>
      </tr>
    </thead>
    <tbody>
      <c:forEach var="owner" items="${owners}">
        <tr>
          <td><c:out value="${owner.firstName} ${owner.lastName}" /></td>
          <td><c:out value="${owner.ssn}" /></td>
          <td><c:out value="${owner.email}" /></td>
          <td><c:out value="${owner.phone}" /></td>
        </tr>
      </c:forEach>
    </tbody>
  </table>

  <hr>

  <form method="POST">
    <p>First Name: <input name="firstName" /><br></p>
    <p>Last Name: <input name="lastName" /><br></p>
    <p>SSN: <input name="ssn" /><br></p>
    <p>Email: <input name="email" /><br></p>
    <p>Phone: <input name="phone" /><br></p>
    <input type="submit" value="Create Owner" />
  </form>
  <hr>
  <a href="${pageContext.request.contextPath}">Home</a>
</body>
</html>

As you can see, it a very simple page. It lists all the owners and provides a form for us to create owners.
Although JSP allows you to execute codes with the <% %> brackets, please don’t do it!
A view should only focus on how to display the attributes.
A view should not involve any of those business logics.

Change the <body /> of app/views/index.jsp with following content:

<body>
  <h1>Bank</h1>
  <hr>
  <a href="owners">Manage Owners</a>
  <a href="accounts">Manage Accounts</a>
</body>

You can review AccountsController.java and app/views/accounts/index.jsp by yourself.

Now start the Tomcat and open your browser.
owners-index

Step 14 – testing with MockMVC

git checkout -f step-14

We completed our demo application by last step. Let’s complete our tests now.

OwnersControllerTest

public class OwnersControllerTest {
  MockMvc mockMvc;
  @InjectMocks
  OwnersController controller;
  @Mock
  OwnerService ownerService;

  @Before
  public void setUp() throws Exception { ... }

  @Test
  public void getIndex() throws Exception { ... }

  @Test
  public void postCreate() throws Exception {
    when(
        ownerService.addOwner(any(String.class), any(String.class),
            any(String.class), any(String.class), any(String.class)))
        .thenReturn(true);
    when(ownerService.getAllOwners()).thenReturn(new ArrayList());
    mockMvc
        .perform(
            post("/owners").param("firstName", "John").param("lastName", "Doe")
                .param("ssn", "123-456-7890").param("email", "")
                .param("phone", "")).andExpect(status().isOk())
        .andExpect(view().name("owners/index"))
        .andExpect(model().attribute("owners", emptyList()));
  }
}

Controllers often interact with many services and services often interact with databases or internet connections. If you needs to prepare an entire model layer before testing controllers, it would be too expensive.
With Mockito and MockMVC, we can easily focus on the testing of controllers now.
Don’t forget to mock the behavior of services, otherwise you won’t get a reasonable outcome from your tests of controllers.

The AccountsControllerTest is just like this one. Try to implement a AccountsControllerTest by yourself before you read it.

Step 15 – integration test

git checkout -f step-15

Every parts of our application is fully tested. We can now be confident if we want to run our application in production. However the world is more complicated than we thought, we need an approach to emulate the condition for our application to run in the battlefield. In the end, we come up with the integration test.

New dependencies:

<dependency>
  <groupId>org.dbunit</groupId>
  <artifactId>dbunit</artifactId>
  <version>2.4.9</version>
  <scope>test</scope>
  <exclusions>
    <exclusion>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
    </exclusion>
  </exclusions>
</dependency>

DBUnit is a great tool for database testings. It allows you to pre-populate your database with XML files and other data formats.

<dependency>
  <groupId>com.github.springtestdbunit</groupId>
  <artifactId>spring-test-dbunit</artifactId>
  <version>1.0.1</version>
  <scope>test</scope>
</dependency>

Integrate DBUnit with the Spring Framework.

Q: How’s the integration test to be done?
A: Much like the controller testing. Instead of mocking things all around, we instantiate most of objects for real.

OwnersControllerIntegrationTest.java

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/context.xml" })
@WebAppConfiguration
@TransactionConfiguration(defaultRollback = true)
@Transactional
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
    DirtiesContextTestExecutionListener.class,
    TransactionalTestExecutionListener.class, DbUnitTestExecutionListener.class })
public class OwnersControllerIntegrationTest {
  MockMvc mockMvc;
  @Inject
  OwnersController controller;
  @Inject
  OwnerDAO dao;

  @Before
  public void setUp() throws Exception {
    mockMvc = standaloneSetup(controller).build();
  }

  @DatabaseSetup("classpath:datasets/owner.xml")
  @Test
  public void getIndex() throws Exception {
    mockMvc.perform(get("/owners")).andExpect(status().isOk())
        .andExpect(view().name("owners/index"))
        .andExpect(model().attribute("owners", dao.findAll()));
  }

  @Test
  public void postCreate() throws Exception {
    mockMvc
        .perform(
            post("/owners").param("firstName", "John").param("lastName", "Doe")
                .param("ssn", "123-456-7890").param("email", "")
                .param("phone", "")).andExpect(status().isOk())
        .andExpect(view().name("owners/index"))
        .andExpect(model().attribute("owners", dao.findAll()));
  }
}

This test emulates all the actions behind the scene. The real request, the real process, the real transaction and the real database, everything is real.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/context.xml" })
@WebAppConfiguration

We are not mocking anymore, so we have to provide the real configuration for Spring.
Although it’s an integration test, please don’t use the production database!

@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
    DirtiesContextTestExecutionListener.class,
    TransactionalTestExecutionListener.class, DbUnitTestExecutionListener.class })

This annotations are added for spring-test-dbunit.

@DatabaseSetup("classpath:datasets/owner.xml")

This annotation pre-populates the database before this test running.

owner.xml

<?xml version="1.0" encoding="UTF-8"?>
<dataset>
  <owner id="1" first_name="aaa" last_name="bb" ssn="111-111-1111" email="" phone="" />
  <owner id="2" first_name="ccc" last_name="dd" ssn="222-222-2222" email="" phone="" />
</dataset>

It’s time for you to write an integration test for the AccountsController.
After you are done, congratulations! You’ve got all the basic about the Java testing.

The percentage of testing codes in this demo
percentage-of-testing-codes
Usually the testing codes are more than the main codes in your applications. In my experience, the testing codes is about 60% of your total lines of codes if you achieve 90%+ code coverage.

Video | Posted on by | Leave a comment

JavaScript engine benchmarks: Nashorn vs V8 vs Spidermonkey

Environment:

Macbook Air 11′ Mid 2012

Processor: 1.7 GHz Intel Core i5

Memory: 8 GB 1600 MHz  DDR3OS X 10.9 (Maverick)

Test Frameworks:

Octane 2.0 http://octane-benchmark.googlecode.com/svn/latest/index.html

SunSpider 1.0.2 http://www.webkit.org/perf/sunspider/sunspider.html

JavaScript Engines:

JavaFX 8 (build 1.8.0-ea-b118) WebView (Nashorn)

Google Chrome 31.0.1650.63 (V8)

Mozilla Firfox 25.0.1 (Spidermonkey)

Benchmarks:

Octane 2.0

Nashorn

Score: 9307

Richards: 13037
Deltablue: 12483
Crypto: 15042
Raytrace: 16411
EarleyBoyer: 21232
Regexp: 1013
Splay: 7395
SplayLatency: 4596
NavierStrokes: 14161
pdf.js: 7918
Mandreel: 7902
MandreelLatency: 3693
GB Emulator: 12663
CodeLoad: 9070
Box2DWeb : 12783
zlib: 12896
Typescript: 16212

V8

Score: 14474

Richards: 20673
Deltablue: 21541
Crypto: 17650
Raytrace: 31598
EarleyBoyer: 28439
Regexp: 2752
Splay: 7758
SplayLatency: 15295
NavierStokes: 19421
pdf.js: 12779
Mandreel: 1421
MandreelLatency: 11567
GB Emulator: 19491
CodeLoad: 11828
Box2DWeb: 13329
zlib: 12958
Typescript: 14335

Spidermonkey

Score: 10066

Richards: 13447
Deltablue: 12291
Crypto: 14056
Raytrace: 13542
EarleyBoyer: 10190
Regexp: 1110
Splay: 9160
SplayLatency: 4258
NavierStokes: 17737
pdf.js: 6881
Mandreel: 9403
MandreelLatency: 12526
GB Emulator: 22469
CodeLoad: 11848
Box2DWeb: 10833
zlib: 32793
Typescript: 5924

SunSpider 1.0.2

Nashorn

============================================
RESULTS (means and 95% confidence intervals)
——————————————–
Total:                 256.2ms +/- 5.6%
——————————————–

  3d:                   38.4ms +/- 7.1%
    cube:               14.6ms +/- 13.1%
    morph:              10.6ms +/- 16.0%
    raytrace:           13.2ms +/- 10.1%

  access:               19.2ms +/- 4.2%
    binary-trees:        1.9ms +/- 11.9%
    fannkuch:            7.9ms +/- 2.9%
    nbody:               4.5ms +/- 11.2%
    nsieve:              4.9ms +/- 10.8%

  bitops:               14.5ms +/- 7.4%
    3bit-bits-in-byte:   2.0ms +/- 0.0%
    bits-in-byte:        2.8ms +/- 16.1%
    bitwise-and:         4.2ms +/- 7.2%
    nsieve-bits:         5.5ms +/- 14.0%

  controlflow:           2.6ms +/- 26.6%
    recursive:           2.6ms +/- 26.6%

  crypto:               24.7ms +/- 10.3%
    aes:                11.6ms +/- 13.1%
    md5:                 7.5ms +/- 13.7%
    sha1:                5.6ms +/- 15.0%

  date:                 29.1ms +/- 14.8%
    format-tofte:       16.5ms +/- 19.0%
    format-xparb:       12.6ms +/- 17.0%

  math:                 25.2ms +/- 5.8%
    cordic:              4.8ms +/- 13.7%
    partial-sums:       17.2ms +/- 8.9%
    spectral-norm:       3.2ms +/- 20.5%

  regexp:               10.6ms +/- 8.5%
    dna:                10.6ms +/- 8.5%

  string:               91.9ms +/- 11.6%
    base64:              7.9ms +/- 16.8%
    fasta:              16.7ms +/- 19.7%
    tagcloud:           18.1ms +/- 14.4%
    unpack-code:        39.0ms +/- 11.3%
    validate-input:     10.2ms +/- 16.4%

V8

============================================
RESULTS (means and 95% confidence intervals)
——————————————–
Total:                 220.8ms +/- 2.6%
——————————————–

  3d:                   34.8ms +/- 6.3%
    cube:               13.2ms +/- 8.0%
    morph:               7.7ms +/- 6.3%
    raytrace:           13.9ms +/- 7.8%

  access:               19.2ms +/- 4.6%
    binary-trees:        2.0ms +/- 0.0%
    fannkuch:            9.7ms +/- 6.1%
    nbody:               3.4ms +/- 10.9%
    nsieve:              4.1ms +/- 9.9%

  bitops:               16.8ms +/- 4.4%
    3bit-bits-in-byte:   2.0ms +/- 0.0%
    bits-in-byte:        5.5ms +/- 6.8%
    bitwise-and:         4.1ms +/- 5.5%
    nsieve-bits:         5.2ms +/- 8.7%

  controlflow:           3.1ms +/- 7.3%
    recursive:           3.1ms +/- 7.3%

  crypto:               22.3ms +/- 6.9%
    aes:                 7.9ms +/- 9.0%
    md5:                 7.1ms +/- 12.1%
    sha1:                7.3ms +/- 8.1%

  date:                 21.8ms +/- 6.1%
    format-tofte:       11.9ms +/- 10.4%
    format-xparb:        9.9ms +/- 6.3%

  math:                 18.7ms +/- 7.4%
    cordic:              4.4ms +/- 11.4%
    partial-sums:       10.4ms +/- 12.2%
    spectral-norm:       3.9ms +/- 5.8%

  regexp:                8.7ms +/- 5.5%
    dna:                 8.7ms +/- 5.5%

  string:               75.4ms +/- 3.7%
    base64:              7.0ms +/- 9.6%
    fasta:               7.6ms +/- 6.6%
    tagcloud:           27.0ms +/- 3.7%
    unpack-code:        25.5ms +/- 4.8%
    validate-input:      8.3ms +/- 9.1%

Spidermonkey

============================================
RESULTS (means and 95% confidence intervals)
——————————————–
Total:                 246.5ms +/- 3.6%
——————————————–

  3d:                   37.8ms +/- 8.3%
    cube:               15.1ms +/- 8.5%
    morph:               6.4ms +/- 7.8%
    raytrace:           16.3ms +/- 9.0%

  access:               24.0ms +/- 7.7%
    binary-trees:        3.1ms +/- 13.1%
    fannkuch:            9.3ms +/- 10.3%
    nbody:               4.3ms +/- 8.0%
    nsieve:              7.3ms +/- 12.3%

  bitops:               12.2ms +/- 4.6%
    3bit-bits-in-byte:   1.7ms +/- 28.4%
    bits-in-byte:        3.0ms +/- 0.0%
    bitwise-and:         2.6ms +/- 14.2%
    nsieve-bits:         4.9ms +/- 4.6%

  controlflow:           3.0ms +/- 0.0%
    recursive:           3.0ms +/- 0.0%

  crypto:               20.7ms +/- 2.8%
    aes:                10.3ms +/- 3.4%
    md5:                 5.8ms +/- 7.8%
    sha1:                4.6ms +/- 8.0%

  date:                 35.5ms +/- 19.9%
    format-tofte:       18.4ms +/- 28.7%
    format-xparb:       17.1ms +/- 32.3%

  math:                 14.5ms +/- 3.5%
    cordic:              3.4ms +/- 10.9%
    partial-sums:        8.0ms +/- 4.2%
    spectral-norm:       3.1ms +/- 7.3%

  regexp:               17.7ms +/- 17.6%
    dna:                17.7ms +/- 17.6%

  string:               81.1ms +/- 13.3%
    base64:              7.9ms +/- 9.0%
    fasta:               8.4ms +/- 5.9%
    tagcloud:           22.4ms +/- 22.1%
    unpack-code:        30.2ms +/- 20.8%
    validate-input:     12.2ms +/- 56.6%

Posted in javascript | Tagged , | Leave a comment

Ruby ==, hash VS Java equals, hashCode

We should take a look what equals() & hashCode() of Java did for us.

We create a simple Java class first.

public class Demo {
  private int i;
  public Demo(int i) { this.i = i; }
}

Let test it with a Set.

Set<Demo> set = new HashSet<Demo>();
set.add(new Demo(1));
set.add(new Demo(1));
System.out.println(set.size()); // Output: 2

It obvioudly not the result we want.
2 Demo objects contain the same variable i, the set should only hold one copy of it.
In other words, the size of the set should be 1.

What’s going on?
Every object of Java inherites the default implementation of equals() fom Object class.

It only tells if 2 objects are equal by comparing their indentities(they’re usually the memory addresses).

Although 2 objects hold the same content, they are not the same by the default implementation of equals().

Fix it!

public class Demo {
  private int i;
  public Demo(int i) { this.i = i; }
  @Override
  public boolean equals(Object o) {
    if (o instanceof Demo) {
      Demo demo = (Demo) o;
      return i == demo.i;
    }
    return false;
  }
}

System.out.println(new Demo(1).equals(new Demo(1))); // Output: true

Then do it again.

Set<Demo> set = new HashSet<Demo>();
set.add(new Demo(1));
set.add(new Demo(1));
System.out.println(set.size()); // Output: 2

The output is still 2. What happened?
It’s because HashSet is based on the hashCode() function to implement.
We have to ensure that any 2 equal objects must get the same hash code value.
In doing so, all HashSet, HashMap, LinkedHashMap… in Java will start to work correctly.

Fix it again!

public class Demo {
  private int i;
  public Demo(int i) { this.i = i; }
  ...
  @Override
  public int hashCode() {
    return 7 * 31 + i;
  }
}

System.out.println(new Demo(1).hashCode() == new Demo(1).hashCode()); // Output: true

See the result.

Set<Demo> set = new HashSet<Demo>();
set.add(new Demo(1));
set.add(new Demo(1));
System.out.println(set.size()); // Output: 1

Finally it works!

This concept can also be used in Ruby, but Ruby proogrammers tend to forget overwriting them.

Let write a simple Ruby class

class Demo
  attr_reader :i
  def initialize(i)
    @i = i
  end
end

We can see the samething happened again.

p Demo.new(1) == Demo.new(1)
=> false
p Demo.new(1).hash == Demo.new(1).hash
=> false

Fix it.

class Demo
  attr_reader :i
  def initialize(i)
    @i = i
  end

  def ==(o)
    if o.kind_of? Demo
      return @i == o.i
    end
    false
  end

  def hash
    7 * 31 + @i
  end
end

It works properly now!

p Demo.new(1) == Demo.new(1)
=> true
p Demo.new(1).hash == Demo.new(1).hash
=> true
Posted in java, ruby | Leave a comment

Iterator Pattern

In my opnion, Iterator Pattern is probably one of the most powerful design patterns in the word of programming.

Why we need the Iterator Pattern?
1. It generalizes and simplifies the way of accessing elements.
2. We can represent a collection of objects with a iterator, but we don’t need to actually load it before we use it.

In Java, the Iterator interface is super simple:

public interface Iterator<E> {
  boolean hasNext();
  E next();
  void remove(); // Optional
}

If we need to iterate a List infinetely, what can we do?
Bad practice 1: Create a infinite List. (It’s insane!)

List<Integer> intList = new LinkedList<Integer>();
while(true) {
  intList.add(Math.random() * 100);
}

Bad practice 2: Loop a List infinetely. (Yes, it works, but you hava to know what you are gonna to do first and the application will be held.)

List<Integer> intList = new ArrayList<Integer>(Arrays.asList(1, 2, 3, 4));
while(true) {
  for(Integer i : intList) {
    // do somthing with i...
  }
}

Solution: How about we create an infinite Iterator called CycleIterator:

public class CycleIterator<E> implements Iterator<E> {

  private final Iterable<E> iterable;
  private Iterator<E> iterator;

  public CycleIterator(Iterable<E> iterable) {
    if (iterable == null)
      throw new NullPointerException();

    this.iterable = iterable;
    iterator = iterable.iterator();
  }

  @Override
  public boolean hasNext() {
    if (!iterator.hasNext())
      iterator = iterable.iterator();

    return iterator.hasNext();
  }

  @Override
  public E next() {
    if (!hasNext())
      throw new NoSuchElementException();

    return iterator.next();
  }

  @Override
  public void remove() {
    throw new UnsupportedOperationException();
  }

}

What we can do now?

List<Integer> intList = new ArrayList<Integer>(Arrays.asList(1, 2, 3, 4));
Iterator<Integer> cycleIter = new CycleIterator<Integer>(intList);
for(int i = 0; i <= 1000; i++)
  System.out.println(cycleIter.next());
...
for(int i = 0; i <= 10000; i++)
  System.out.println(cycleIter.next());
...
for(int i = 0; i <= 100000; i++)
  System.out.println(cycleIter.next());
...

Eventually, we can now iterate this infinity collection in any place of code we want.

Moreover, we can make it into an Iterable. (Note: An Iterable is simply an object which can provide an Iterator.)

public class CycleIterable<E> implements Iterable<E> {

  private Iterable<E> iterable;

  public CycleIterable(Iterable<E> iterable) {
    this.iterable = iterable;
  }

  @Override
  public Iterator<E> iterator() {
    return new CycleIterator<E>(iterable);
  }

}
Posted in design pattern, java | Leave a comment

rubycollect4j – Ruby Collections for Java

As a Ruby programmer, I am fascinating by the friendly APIs which Ruby array & hash provide.

As a Java programmer, I am confident with the power and reliability it brings.

I tried JRuby and developed few Rails applications. Frankly speaking, it brought me a pretty good experience.

But when I am working on a pure Java project, JRuby doesn’t help much then.

In the end, I made my self a solution which is rubycollect4j, a pure Java library which implements all the methods refer to the Ruby array & hash.

 

For example:
It’s very easy to find 2 words which get the least and the most unique letters in a linux dictionary with Ruby.

File.foreach('/usr/share/dict/web2')
  .minmax_by { |word| word.chars.uniq.count }.map!(&:strip)
=> ["A", "blepharoconjunctivitis"]

Now you can do exactly the same thing in Java.

RubyFile.foreach("/usr/share/dict/web2")
  .minmaxBy(new TransformBlock<String, Integer>() {
    public Integer yield(String item) {
      return newRubyArray(item.split("(?!^)")).uniq().count();
    }
  });

It even looks better with Java 8:

RubyFile.foreach("/usr/share/dict/web2").minmaxBy((item) -> {
  return newRubyArray(item.split("(?!^)")).uniq().count();
});

 

The useful lazy loading feature in Ruby 2.0:

(1..100).lazy.cycle.first(10)

It’s fully available in Java now.

range(1, 100).lazy().cycle().first(10);

 

If now you have the same feeling as I do, visit my project home:

https://github.com/wnameless/rubycollect4j/

Posted in java, ruby | Tagged , , , | Leave a comment