Along side of development lifecycle, most of us looking for a way to be sure that the unit of work that has been written is working properly and committed to its contract. This is actually may be much easier when you come to work with one class and one object as well. But what if you have a massive amount of components that contain a huge set of methods that should be examined.
This isn’t the whole picture, while most of software have developed gradually, no one can assure you that he/she has the whole business components before getting started the development process. This will be carrying with some complexity as the implementation of one class may be evolved several times and every time it needs to be re-examined that it’s working properly and that evolution doesn’t break its core functionality.
Upon that, how much complexity you may face there to re-examine certain class several time to make sure it’s not broken due to certain enhancements you did intentionally or unintentionally – as a normal result for gradual evolving. This is actually the job of JUnit framework and all of its relevant ones that are built on;
JUnit is an open source software that help you generate Test Cases that can be executed easily, consistently and effectively to verify that your component works as expected and to catch the bugs earlier.
A lot of frameworks are developed upon JUnit; frameworks like HttpUnit, ServeltUnit, JSFUnit, JWebUnit .. and others, are samples for those software that you may use to verify your components regardless whether your components are so simple or it needs specific container to function.
Here, you will find all what you need to understand the basic terminology of JUnit and use its features effectively. Beside that, you will see how to verify a simple Java Class, Web Page, Portlet and JSF components using JUnit, JWebUnit and JSFUnit (Arquillian) respectively.
Following below main bullets that will be discussed at this Tutorial as you may navigate into that one you need directly:
To make sure you will be fully aware of all concepts that this tutorial is going to discuss, be sure that you have read these below also:
- JSF Beginner Tutorial which will help you understanding the basic concepts about JSF framework and clarify you the most easy sample.
- Apache Pluto Tutorial while will help you understanding the basic concepts about Portlet, Portlet Container and clarify you HelloWorld Portlet.
Setting Up JUnit
Setting up of JUnit isn’t much more than adding two JARs into your compilation path and execution path. Following below steps all what you need:
- Download JUnit JAR from Maven Central Repository.
- Download hamcrest library from Maven Central Repository. JUnit actually depends on this library for more attractive, easy and clear assertions.
- Adding JUnit and hamcrest libraries into your classpath. The most easiest way that you may use is by setting these libraries beneath your JDK extension directory.
- Specify to which JDK your environment has been referring. JAVA_HOME variable should help.
- Specify the location of JDK extension, always you should be able to find this path beneath your JDK directory. %JAVA_HOME%jrelibext.
-
- Be sure that you have JUnit library inside your classpath by invoking
java -verbose
against console which will print out all loaded classes instantly.
- Be sure that you have JUnit library inside your classpath by invoking
Execution of java -verbose
[Loaded org.junit.runner.JUnitCore from file:/C:/Program%20Files/Java/jdk1.6.0_26/jre/lib/ext/junit-4.12.jar]
[Loaded org.junit.runner.notification.RunListener from file:/C:/Program%20Files/Java/jdk1.6.0_26/jre/lib/ext/junit-4.12.jar]
[Loaded org.junit.internal.TextListener from file:/C:/Program%20Files/Java/jdk1.6.0_26/jre/lib/ext/junit-4.12.jar]
[Loaded org.junit.runner.Describable from file:/C:/Program%20Files/Java/jdk1.6.0_26/jre/lib/ext/junit-4.12.jar]
[Loaded org.junit.runner.Runner from file:/C:/Program%20Files/Java/jdk1.6.0_26/jre/lib/ext/junit-4.12.jar]
[Loaded org.junit.runner.manipulation.Filterable from file:/C:/Program%20Files/Java/jdk1.6.0_26/jre/lib/ext/junit-4.12.jar]
[Loaded org.junit.runner.manipulation.Sortable from file:/C:/Program%20Files/Java/jdk1.6.0_26/jre/lib/ext/junit-4.12.jar]
[Loaded org.junit.internal.runners.JUnit38ClassRunner from file:/C:/Program%20Files/Java/jdk1.6.0_26/jre/lib/ext/junit-4.12.jar]
[Loaded org.junit.internal.JUnitSystem from file:/C:/Program%20Files/Java/jdk1.6.0_26/jre/lib/ext/junit-4.12.jar]
[Loaded org.junit.runner.Computer from file:/C:/Program%20Files/Java/jdk1.6.0_26/jre/lib/ext/junit-4.12.jar]
[Loaded org.junit.runners.model.RunnerBuilder from file:/C:/Program%20Files/Java/jdk1.6.0_26/jre/lib/ext/junit-4.12.jar]
[Loaded org.junit.runner.Computer$1 from file:/C:/Program%20Files/Java/jdk1.6.0_26/jre/lib/ext/junit-4.12.jar]
[Loaded org.junit.runners.ParentRunner from file:/C:/Program%20Files/Java/jdk1.6.0_26/jre/lib/ext/junit-4.12.jar]
[Loaded org.junit.runners.Suite from file:/C:/Program%20Files/Java/jdk1.6.0_26/jre/lib/ext/junit-4.12.jar]
[Loaded org.junit.runner.notification.RunNotifier from file:/C:/Program%20Files/Java/jdk1.6.0_26/jre/lib/ext/junit-4.12.jar]
[Loaded org.junit.runner.notification.SynchronizedRunListener from file:/C:/Program%20Files/Java/jdk1.6.0_26/jre/lib/ext/junit-4.12.jar]
[Loaded org.junit.runner.notification.StoppedByUserException from file:/C:/Program%20Files/Java/jdk1.6.0_26/jre/lib/ext/junit-4.12.jar]
- Create the most simple Test Case like below
HelloWorldTestCase.java
import org.junit.Test;
import static org.junit.Assert.*;
public class HelloWorldTestCase {
@Test
public void testHelloWorld(){
// Print a message before assertion
System.out.println("Before Getting Test Started ::");
// If assertion goes wrong, the execution of Test would fail
assertEquals("Would Say Hello","Hello","Hello");
// Print a message after execution of Test; if assertion goes well, this message would be shown
System.out.println("After Test Execution ::");
}
public static void main(String [] args){
// JUnitCore is provided by JUnit to run your Tests through consols
org.junit.runner.JUnitCore.runClasses(HelloWorldTestCase.class);
}
}
- Open your console and compile the class and then execute it. We have used assertEquals which should compare values of last two arguments (
Invoking equals()
). More later. - JUnitCore is a class provided by JUnit to allow you run and display your result via console directly.
- Invoke Java compilation and interpretation respectively against your HelloWorldTestCase.
- If you have got arguments changed (for example hello and Hello) you would of course see the below result:
- Second message wasn’t showed due to assertion failure.
- Don’t consume your time understanding what you had seen on the HelloWorldTestCase, as most of these components/annotations would be subject of next sections.
Setting your library inside your JDK extension should be much helper than providing them while program execution. This concept is so relevant of the ClassLoader and the way in which it loads the libraries and at which level the extension directory comes.
Leverage JUnit Through Eclipse
Even though you may find JUnit so beautiful while using it through your command console, but when you leverage it inside your Eclipse you will be wondering from these facilities Eclipse can provide which surely will lead you to leave the console without revert.
Eclipse IDE doesn’t only provide a way to execute your JUnit’s Test Cases properly, but it also provides you a brilliant graphical user interface that would give you indicators whether Test Cases you had ran are finished successfully.
Following below, required steps that would lead you for proper usage of JUnit from within Eclipse IDE.
- Remove JUnit and hamcrest JARs from JDK extension so that you will refer those provided by Eclipse itself. Be sure they are removed by invoking
java -verbose
and looking for JUnit. - Install Eclipse IDE, for this tutorial i’ll use Eclipse Kepler.
- Create most simple Maven project, by using Eclipse embedded Maven quickstart archetype.
It supposed to be familiar with Maven, but for those aren’t. Maven is a build tool that can help you generating executable binaries, managing project’s dependencies and much more. Maven also provides you a way to create a standard project with a ready-made internal structure.
- Fill in all required information, groupId, artifactId and package and then finish.
- Make sure your project created recently doesn’t show any issue or errors. In case yes, it shows, just remove parent section as most of these archetypes are too old.
- Your created project will be having a reference for a JUnit library which is absolutely too old and it needs some refinement. Open your pom file and change version of JUnit library to be 4.12 and add hamcrest maven dependency. Your pom file should be looks like below:
pom.xml
<?xml version="1.0"?>
<project
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>com.journaldev</groupId>
<artifactId>HelloWorldTestCase</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>HelloWorldTestCase</name>
<url>https://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<version>1.3</version>
</dependency>
</dependencies>
</project>
- Do a normal clean for your project so that these referenced JARs have been installed.
- Notice that you have inside your project two packages; one represents your classes while other represents Test Cases. I recommend highly delete them for now, so that you may start cleanly.
Don’t give com.journaldev package that’s located beneath src/test/java any care as we will have a separate section that shows you how can integrate your JUnit TestCases with Maven build tool.
- Create HelloWorldTestCase class that you had created before inside your project and beneath your package.
HelloWorldTestCase.java
package com.journaldev;
import org.junit.Test;
import static org.junit.Assert.*;
public class HelloWorldTestCase {
@Test
public void testHelloWorld(){
// Print a message before assertion
System.out.println("Before Getting Test Started ::");
// If assertion goes wrong, the execution of Test would fail
assertEquals("Would Say Hello","Hello","Hello");
// Print a message after execution of Test; if assertion goes well, this message would be shown
System.out.println("After Test Execution ::");
}
public static void main(String [] args){
// JUnitCore is provided by JUnit to run your Tests through console
org.junit.runner.JUnitCore.runClasses(HelloWorldTestCase.class);
}
}
- Compile your project and make sure that you don’t have any errors.
- To execute your project, you have two options:
- Execute it normally just like you did above with any normal Java class that have main method.
- Execute it using Eclipse IDE’s JUnit facility.
- Executing the project using the first way would lead you for below result (CTRL + SHIFT + x & j):
- Executing the project using the second way would lead you for below nice result (CTRL + SHIFT + x & t:
- As you notice above, there’s now an indicators tell you the result of TestCase beside the above messages on the console.
JUnit Annotations; @Test, @Before, @After, @AfterClass, @BeforeClass
From now on, no need to use JUnit through using basic command console, rather consume your time preparing your TestCases and provide a way to run it, use Eclipse directly and enjoy seeing these indicators.
This usage doesn’t consider defining a main method, thereby, you should use CTRL + SHIFT + x & t at each time you want to execute your Tests.
After all of these clarifications that were introduced in previous sections, it’s now the time to focus deeply at JUnit concepts and its various features.
To define a TestCase within your class, you shall use @Test annotation in conjunction with your defined method. That class and this method should have the following rules:
- Your class must be defined as public and have a default constructor (zero argument).
- Your Test method should be defined as a public, take no arguments and return void.
Once JUnit framework has met an @Test annotation, it will create an instance of that class that is containing that method and invoking the @Test annotated method. This is the philosophy of JUnit and how it works.
If your Test class has two methods annotated with @Test, this means JUnit will create two instances to invoke both of them and so on. Due to this fact, you can’t reuse instance variables values across test methods.
JUnit framework judge certain @Test method by calling assertion(s) it contains, so that be sure that every @Test method has called specific assertions to eliminate any confusion. This confusion happens when you get a result that specific @Test method returns success while no assertions was used there.
It’s not recommended providing one more assertion within @Test method, so that you will know exactly which TestCase has failed and due to what it’s got. But actually no constraints has been applied from the JUnit framework itself.
You have seen how can one @Test method be used, but let’s now see how can we collaborate one more @Test method simultaneously.
HelloWorldTestCase.java
package com.journaldev;
import org.junit.Test;
import static org.junit.Assert.*;
public class HelloWorldTestCase {
@Test
public void testHelloWorldOne(){
// Print a message before assertion
System.out.println("Before Getting Test #1 Started ::");
// If assertion goes wrong, the execution of Test would fail
assertEquals("Would Say Hello","Hello","Hello");
// Print a message after execution of Test; if assertion goes well, this message would be shown
System.out.println("After Test #1 Execution ::");
}
@Test
public void testHelloWorldTwo(){
// Print a message before assertion
System.out.println("Before Getting Test #2 Started ::");
// If assertion goes wrong, the execution of Test would fail
assertEquals("Would Say Hello","Hello","Hello");
// Print a message after execution of Test; if assertion goes well, this message would be shown
System.out.println("After Test #2 Execution ::");
}
}
Execution of sample above would result in the below:
Execution Result
Before Getting Test #1 Started ::
After Test #1 Execution ::
Before Getting Test #2 Started ::
After Test #2 Execution ::
- As you may notice, two TestCases are executed and the result is drawn through JUnit’s Eclipse indicators.
But what i you want some prior/posterior executions for your Tests, something executed right before or/and after of any @Test method and without any respect being @Test has finished successfully or not. Then, you should use @Before and @After, respectively. Let’s now see how it works after adding these methods that are annotated with @Before and @After.
HelloWorldTestCase.java
package com.journaldev;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
public class HelloWorldTestCase {
@Before
public void beforeExecutingTestCase(){
System.out.println("Before Executing Test Case :: ");
}
@After
public void afterExecutingTestCase(){
System.out.println("After Executing Test Case :: ");
}
@Test
public void testHelloWorldOne(){
// Print a message before assertion
System.out.println("Before Getting Test #1 Started ::");
// If assertion goes wrong, the execution of Test would fail
assertEquals("Would Say Hello","Hello","Hello");
// Print a message after execution of Test; if assertion goes well, this message would be shown
System.out.println("After Test #1 Execution ::");
}
@Test
public void testHelloWorldTwo(){
// Print a message before assertion
System.out.println("Before Getting Test #2 Started ::");
// If assertion goes wrong, the execution of Test would fail
assertEquals("Would Say Hello","Hello","Hello");
// Print a message after execution of Test; if assertion goes well, this message would be shown
System.out.println("After Test #2 Execution ::");
}
}
Execution of above should lead you for below:
Execution Result
Before Executing Test Case ::
Before Getting Test #1 Started ::
After Test #1 Execution ::
After Executing Test Case ::
Before Executing Test Case ::
Before Getting Test #2 Started ::
After Test #2 Execution ::
After Executing Test Case ::
You may notice above execution of @Before method and @After, before and after every @Test method.
One important note here and it’s beware from getting multiple @Before and @After methods defined as no one can tell you what’s the order of their execution.
At the other hand, what if you want methods called right before all your @Test methods and after all your @Test methods. This is exactly what you get when you have used @BeforeClass and @AfterClass.
HelloWorldTestCase.java
package com.journaldev;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
public class HelloWorldTestCase {
@BeforeClass
public static void beforeExecutingHelloWorldTestCases(){
System.out.println("Before Executing HelloWorldTestCases :: ");
}
@AfterClass
public static void afterExecutingHelloWorldTestCases(){
System.out.println("After Executing HelloWorldTestCases :: ");
}
@Before
public void beforeExecutingTestCase(){
System.out.println("Before Executing Test Case :: ");
}
@After
public void afterExecutingTestCase(){
System.out.println("After Executing Test Case :: ");
}
@Test
public void testHelloWorldOne(){
// Print a message before assertion
System.out.println("Before Getting Test #1 Started ::");
// If assertion goes wrong, the execution of Test would fail
assertEquals("Would Say Hello","Hello","Hello");
// Print a message after execution of Test; if assertion goes well, this message would be shown
System.out.println("After Test #1 Execution ::");
}
@Test
public void testHelloWorldTwo(){
// Print a message before assertion
System.out.println("Before Getting Test #2 Started ::");
// If assertion goes wrong, the execution of Test would fail
assertEquals("Would Say Hello","Hello","Hello");
// Print a message after execution of Test; if assertion goes well, this message would be shown
System.out.println("After Test #2 Execution ::");
}
}
Execution result for the above will be:
Execution Result
Before Executing HelloWorldTestCases ::
Before Executing Test Case ::
Before Getting Test #1 Started ::
After Test #1 Execution ::
After Executing Test Case ::
Before Executing Test Case ::
Before Getting Test #2 Started ::
After Test #2 Execution ::
After Executing Test Case ::
After Executing HelloWorldTestCases ::
As you may notice that @BeforeClass and @AfterClass methods have been called once before and after of all your @Test methods.
Timeout & Expected
You have seen how annotations like @Test, @Before, @After, @BeforeClass and @AfterClass be used withing JUnit framework. This section will focus on discussing how a Test case can be await for specific time before got failed and how it can be handle certain exceptions.
Though no specific annotations could be used but @Test would have now additional attributes that you may use for resolving these features.
Timeout argument is passed for @Test annotation to specify to which millisecond(s) this method will be waiting before get failed. This is actually so helpful when you’re going to examine and verify performance of given code.
Following sample shows you clearly how this could be used:
HelloWorldTestCase.java
package com.journaldev;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
public class HelloWorldTestCase {
@BeforeClass
public static void beforeExecutingHelloWorldTestCases(){
System.out.println("Before Executing HelloWorldTestCases :: ");
}
@AfterClass
public static void afterExecutingHelloWorldTestCases(){
System.out.println("After Executing HelloWorldTestCases :: ");
}
@Before
public void beforeExecutingTestCase(){
System.out.println("Before Executing Test Case :: ");
}
@After
public void afterExecutingTestCase(){
System.out.println("After Executing Test Case :: ");
}
@Test
public void testHelloWorldOne(){
// Print a message before assertion
System.out.println("Before Getting Test #1 Started ::");
// If assertion goes wrong, the execution of Test would fail
assertEquals("Would Say Hello","Hello","Hello");
// Print a message after execution of Test; if assertion goes well, this message would be shown
System.out.println("After Test #1 Execution ::");
}
@Test
public void testHelloWorldTwo(){
// Print a message before assertion
System.out.println("Before Getting Test #2 Started ::");
// If assertion goes wrong, the execution of Test would fail
assertEquals("Would Say Hello","Hello","Hello");
// Print a message after execution of Test; if assertion goes well, this message would be shown
System.out.println("After Test #2 Execution ::");
}
@Test(timeout=1)
public void testWaitForATime(){
// Print statement
System.out.println("@Test Will Be Waiting For 100 Milliseconds :: Supposed Task Should Be Done Before Timeout");
// Some adhoc processing
for(int i = 0 ; i < 1000 ; i++){
Math.random();
}
// Print statement
System.out.println("Task Done Before Timeout :: This Test Has Finished Sucessfully ::");
}
}
Here’s detailed information for the code listed above:
- By providing timeout argument, now it could be executing Test method that wouldn’t be exceed specific amount of time (by milliseconds).
- If execution of this method exceeds the specific amount of milliseconds it would fail even if there’s no failure resulted by certain assertion within that method.
- If execution of this method doesn’t exceed the specific amount of milliseconds it would pass successfully if there’s no failure resulted by certain assertion.
- Setting timeout to 1000 would cause this Test to be finished successfully, while setting it to 10000 wouldn’t.
This is all about timeout and how to specify it in conjunction with @Test annotation. But what if you want certain Test method to be failed if certain exception isn’t thrown or vice versa; at certain exception should be considered success.
This is actually what you’re about when you used expected argument. Following sample shows you a Test method that generates a number and find the result of % 2 to specify if that number is even or not. In case it’s even, a String variable will be initialized, otherwise it’s not.
HelloWorldTestCase.java
package com.journaldev;
import java.io.File;
import java.io.UnsupportedEncodingException;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
public class HelloWorldTestCase {
@BeforeClass
public static void beforeExecutingHelloWorldTestCases(){
System.out.println("Before Executing HelloWorldTestCases :: ");
}
@AfterClass
public static void afterExecutingHelloWorldTestCases(){
System.out.println("After Executing HelloWorldTestCases :: ");
}
@Before
public void beforeExecutingTestCase(){
System.out.println("Before Executing Test Case :: ");
}
@After
public void afterExecutingTestCase(){
System.out.println("After Executing Test Case :: ");
}
@Test
public void testHelloWorldOne(){
// Print a message before assertion
System.out.println("Before Getting Test #1 Started ::");
// If assertion goes wrong, the execution of Test would fail
assertEquals("Would Say Hello","Hello","Hello");
// Print a message after execution of Test; if assertion goes well, this message would be shown
System.out.println("After Test #1 Execution ::");
}
@Test
public void testHelloWorldTwo(){
// Print a message before assertion
System.out.println("Before Getting Test #2 Started ::");
// If assertion goes wrong, the execution of Test would fail
assertEquals("Would Say Hello","Hello","Hello");
// Print a message after execution of Test; if assertion goes well, this message would be shown
System.out.println("After Test #2 Execution ::");
}
@Test(timeout=1)
public void testWaitForATime(){
// Print statement
System.out.println("@Test Will Be Waiting For 100 Milliseconds :: Supposed Task Should Be Done Before Timeout");
// Some adhoc processing
for(int i = 0 ; i < 100 ; i++){
Math.random();
}
// Print statement
System.out.println("Task Done Before Timeout :: This Test Has Finished Sucessfully ::");
}
@Test(expected=NullPointerException.class)
public void testNullPointerExceptionShouldBeRaised() throws UnsupportedEncodingException{
// Define variable
String variable = null;
// Get random number
double value = Math.random() * 100;
// Print out value
System.out.println("Value :: "+(int)value);
if((int)value % 2 == 0){
// Specify variable value
variable = "Even Number";
}
// Print out variable content with UTF-8 encoding
System.out.println("This number is :: "+new String(variable.getBytes(),"UTF-8"));
}
}
Here’d detailed explanation about code listed above:
- To specify whether Test method should generate certain exception or not, you should provide expected argument with the @Test annotation.
- If NullPointerException has been thrown, this Test will be passed successfully. Otherwise, it will fail even if its assertion(s) passed.
Runners & Types of Runners
You did see in the introduction and in the first example how HelloWorldTestCase
works using console command and how it also works from Eclipse by using default normal execution and by using JUnit’s Eclipse built-in features.
Regardless of the way you had chosen to run your TestCases; either by using JUnit command console or by using Eclipse IDE, your TestCases should be ran by using an implementation of Runner.
While we have used org.junit.runner.JUnitCore
to execute our TestCases from command line or by using Eclipse default class execution (i.e. class with main method), Eclipse uses default built-in native graphical runner to execute them.
Following below table summarizes most runners used by JUnit and their respective purposes:
Let’s now see how each type of these Runners might be used and leveraged. You had seen how JUnitCore could be used so that it won’t be discussed once again.
Before getting started explaining different types of Runners, it’s important to discuss firstly the concept of @RunWith
which is used intensively when it comes to use non-default JUnit Runners.
When a class is annotated with @RunWith or extend a class annotated with @RunWith, it will execute its own TestCases using that class mentioned by @RunWith annotation.
That is, if you want to use Parametrized Runner, you should define @RunWith annotation on your class declaration followed with the Parametrized.class
value. Look sample below:
ParametrizedHelloWorldTestCase.java
package com.journaldev;
import static org.junit.Assert.assertEquals;
import java.util.Arrays;
import java.util.Collection;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
public class ParametrizedHelloWorldTestCase{
// Define parametrized's properties
private String expected;
private String actualValue;
public ParametrizedHelloWorldTestCase(String expected, String actualValue) throws Throwable {
// Set values
this.expected = expected;
this.actualValue = actualValue;
}
@Parameters
public static Collection<Object []> dataParameters(){
return Arrays.asList(new Object[][] {
{"Hello World","Hello World"} ,
{"Hi World","HI World"}
});
}
@Test
public void testConcatenation(){
// Print out instance reference and values passed
System.out.println("Instance Reference :: "+this+" :: Expected :: "+this.expected +" :: ActualValue :: "+this.actualValue);
assertEquals(this.expected, this.actualValue);
}
}
Here’s detailed explanation for code listed above before seeing the result of execution:
- @RunWith is used whenever you want to execute your TestCases using non-default Runner. Parametrized is a specialized Runner and therefore, you should define @RunWith followed with the
Paramerized.class
to tell JUnit framework that you’re going to use Parametrized Runner for executing this Test class. - To use Parametrized Runner, you should define the following:
- Define attributes that will be used for passing the parameters. This was done by providing expected and actualValue instance variables.
- Define the method that would be used to populate Test Data; this method should be annotated with @Parameters, it should also be static and return a Collection<Object[]> type.
- Define a parametrized constructor that would be used to assign passed Test Data.
Now, let’s see the output that resulted in from executing such a program above:
It’s so important to note the following points upon the result:
- As you have two pairs of Test Data
{"Hello World","Hello World"}
and{"Hi World","HI World"}
, and according for being @Test is invoked in conjunction with instance creation, thereby you should notice that we have two different instances with two pairs of parameters. Notice object references. - As the first
assertEquals
is expected to be finished properly while second not, it’s so expected to have the following below indicators.
- Two pairs of parameters would initialize two different instances and therefore two different TestCases. If one is failed the whole TestCase would fail as well.
- Creating of these classes and passing respective parameters is the JUnit framework responsibility.
- Number of instances created is equal to number of items defined in the
@Parametrized
method.
Now, let’s look at the second special Runner; it is the suite. If you want to aggregate Test classes, for sure you must use Suite Runner. Following blow sample that shows you how can leverage Suite Runner:
SuiteHelloWorldTestCase.java
package com.journaldev;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class)
@SuiteClasses({HelloWorldTestCase.class,ParametrizedHelloWorldTestCase.class})
public class SuiteHelloWorldTestCase {
}
Here’s detailed explanation for the code listed above:
- Even that you don’t mention any @Test method, but using CTRL + SHIFT + x & t would lead you to execute all TestCases inside both of
HelloWorldTestCase
andParametrizedHelloWorldTestCase
respectively. - Use @Suite and @SuiteClasses for declaring given class as a holder for Test classes and which Test classes should be executed and to which precedence they shall be gone.
- If you were changed precedence of mentioning Test classes, within @SuiteClasses, the precedence of execution would also be changed as well.
- Suite class would remain empty as it’s just a holder for the class’s declaration annotation. That is, if you define an @Test method within Suite class, it wouldn’t be executed anymore.
- Executing of above code would lead you for the below result. This result below shows you all @Test methods executed from one Test class called now suite.
If you understand Suite Runner properly, you should use Category one smoothly and without any issues. All what you have to do is to categorize your Test classes, and specify which Test classes you would to include/exclude in the execution.
It’s so important to know that Category Runner is a special type of Suite, where you should define your Test classes just like you did with Suite special Runner and do the inclusion and exclusion.
Following below full sample with the required steps to use Category Runner:
- Create your categories; which are set of interfaces.
Mandatory.java
package com.journaldev.categories;
public interface Mandatory {
}
Optional.java
package com.journaldev.categories;
public interface Optional {
}
- Annotate your Test classes with the wanted category. For example, created
ParametrizedHelloWorldTestCase
would be annotated as Mandatory whileHelloWorldTestCase
is Optional.
ParametrizedHelloWorldTestCase.java
package com.journaldev;
import static org.junit.Assert.assertEquals;
import java.util.Arrays;
import java.util.Collection;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import com.journaldev.categories.Mandatory;
@RunWith(Parameterized.class)
@Category(Mandatory.class)
public class ParametrizedHelloWorldTestCase{
// Define parametrized's properties
private String expected;
private String actualValue;
public ParametrizedHelloWorldTestCase(String expected, String actualValue) throws Throwable {
// Set values
this.expected = expected;
this.actualValue = actualValue;
}
@Parameters
public static Collection<Object []> dataParameters(){
return Arrays.asList(new Object[][] {
{"Hello World","Hello World"} ,
{"Hi World","Hi World"}
});
}
@Test
public void testConcatenation(){
// Print out instance reference and values passed
System.out.println("Instance Reference :: "+this+" :: Expected :: "+this.expected +" :: ActualValue :: "+this.actualValue);
assertEquals(this.expected, this.actualValue);
}
}
HelloWorldTestCase.java
package com.journaldev;
import static org.junit.Assert.assertEquals;
import java.io.UnsupportedEncodingException;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import com.journaldev.categories.Optional;
@Category(Optional.class)
public class HelloWorldTestCase {
@BeforeClass
public static void beforeExecutingHelloWorldTestCases(){
System.out.println("Before Executing HelloWorldTestCases :: ");
}
@AfterClass
public static void afterExecutingHelloWorldTestCases(){
System.out.println("After Executing HelloWorldTestCases :: ");
}
@Before
public void beforeExecutingTestCase(){
System.out.println("Before Executing Test Case :: ");
}
@After
public void afterExecutingTestCase(){
System.out.println("After Executing Test Case :: ");
}
@Test
public void testHelloWorldOne(){
// Print a message before assertion
System.out.println("Before Getting Test #1 Started ::");
// If assertion goes wrong, the execution of Test would fail
assertEquals("Would Say Hello","Hello","Hello");
// Print a message after execution of Test; if assertion goes well, this message would be shown
System.out.println("After Test #1 Execution ::");
}
@Test
public void testHelloWorldTwo(){
// Print a message before assertion
System.out.println("Before Getting Test #2 Started ::");
// If assertion goes wrong, the execution of Test would fail
assertEquals("Would Say Hello","Hello","Hello");
// Print a message after execution of Test; if assertion goes well, this message would be shown
System.out.println("After Test #2 Execution ::");
}
@Test(timeout=1)
public void testWaitForATime(){
// Print statement
System.out.println("@Test Will Be Waiting For 100 Milliseconds :: Supposed Task Should Be Done Before Timeout");
// Some adhoc processing
for(int i = 0 ; i < 100 ; i++){
Math.random();
}
// Print statement
System.out.println("Task Done Before Timeout :: This Test Has Finished Sucessfully ::");
}
@Test(expected=NullPointerException.class)
public void testNullPointerExceptionShouldBeRaised() throws UnsupportedEncodingException{
// Define variable
String variable = null;
// Get random number
double value = Math.random() * 100;
assertEquals("Would Say Hello","Hello","Hello");
// Print out value
System.out.println("Value :: "+(int)value);
if((int)value % 2 == 0){
// Specify variable value
variable = "Even Number";
}
// Print out variable content with UTF-8 encoding
System.out.println("This number is :: "+new String(variable.getBytes(),"UTF-8"));
}
}
- Providing categories for your created Test classes wouldn’t change anything for them, but they would make them Target for Category Runner. Your Test classes as though would be remain working once CTRL + SHIFT + x & t have been invoked upon them.
CategorizedHelloWorldTestCase.java
package com.journaldev;
import org.junit.experimental.categories.Categories;
import org.junit.experimental.categories.Categories.ExcludeCategory;
import org.junit.experimental.categories.Categories.IncludeCategory;
import org.junit.runner.RunWith;
import org.junit.runners.Suite.SuiteClasses;
import com.journaldev.categories.Mandatory;
import com.journaldev.categories.Optional;
@RunWith(Categories.class)
@IncludeCategory(Mandatory.class)
@ExcludeCategory(Optional.class)
@SuiteClasses({ParametrizedHelloWorldTestCase.class,HelloWorldTestCase.class})
public class CategorizeHelloWorldTestCase {
}
Here’s detailed explanation for code listed above:
- As Category Runner is a special type of suite, so you should use @RunWith but this time with Category.class value.
- @SuiteClasses would hold all Targeted Test classes.
- @IncludeCategory & @ExcludeCategory shall be used to include and exclude Test classes, respectively.
- Executing of Category Runner implemented above would lead you for below result:
- Being @IncludeCategory has mentioned
ParametrizedHelloWorldTestCase
within its parentheses, then it will be executing. - Being @ExecludeCategory has mentioned
HelloWorldTestCase
within its parentheses, then it won’t be executing.
Assertions & Types of Assertions
You did see before using of assert(*)
inside our @Test method, and according of best practices, every @Test method should include one of assert(*) static methods so that the JUnit framework can validate this Test case and makes sure it’s passed or failed.
All of our example was used assertEquals
which is known as a type of assertions that you may use. This section is provided here to help you seeing all types of assertions so that leverage what you want inside your @Test methods.
Following Table shows you the most list of assertions could be used:
Before have discussion for these assertions and how they could be used while using JUnit framework and provide their respective samples. It’s important to know what’s pattern they are followed.
All assertions method have followed the rule: message, expected, result when you’re providing its arguments. That is, passing assertion method’s argument shall be according for that rule.
You should pass the message that assertions would throw once it’s failed followed with the expected value that the assert would act upon and the result (Result of your equation or actual value) that will expected value be compared with.
There’s also a Delta argument that you have used sometimes with some of types of assertions like assertEquals when it takes double arguments. This Delta value is used to determine if your actual value (Result of your equation) is within expected – delta and expected + delta.
Now, following sample shows you all of these mentioned assertions in one full demonstration:
AssertionTypesTestCase.java
package com.journaldev;
import org.junit.Test;
public class AssertionTypesTestCases {
@Test
public void assertEqualArrays(){
// Declare first array
int [] arr1 = {1,2,3,4};
// Declare second array
int [] arr2 = {1,2,3,4};
// Assert
org.junit.Assert.assertArrayEquals("Arrays Aren't Equal ::", arr1, arr2);
}
@Test
public void assertNoEqualArrays(){
// Declare first array
int [] arr1 = {1,2,3,4};
// Declare second array
int [] arr2 = {1,2,3,5};
// Assert
org.junit.Assert.assertArrayEquals("Arrays Aren't Equal ::", arr1, arr2);
}
@Test
public void assertEquals(){
// Declare first object
String message1 = "Hi World";
// Declare second object
String message2 = "Hi World";
// Assert
org.junit.Assert.assertEquals("Objects Aren't Equal ::", message1, message2);
}
@Test
public void assertNotEquals(){
// Declare first object
String message1 = "Hi World";
// Declare second object
String message2 = "HI World";
// Assert
org.junit.Assert.assertEquals("Objects Aren't Equal ::", message1, message2);
}
@Test
public void assertSame(){
// Declare first object
String message1 = "Hi World";
// Declare second object
String message2 = message1;
// Assert
org.junit.Assert.assertSame("Objects Aren't Same ::", message1, message2);
}
@Test
public void assertNotSame(){
// Declare first object
String message1 = "Hi World";
// Declare second object
String message2 = "HI World"; // if you make it Hi World, this assertion would pass
// Assert
org.junit.Assert.assertSame("Objects Aren't Same ::", message1, message2);
}
@Test
public void assertTrue(){
// Declare first object
String message1 = "Hi World";
// Declare second object
String message2 = message1;
// Assert
org.junit.Assert.assertTrue("Result Isn't True ::", message1.equals(message2));
}
@Test
public void assertNotTrue(){
// Declare first object
String message1 = "Hi World";
// Declare second object
String message2 = "Hi World";
// Assert
org.junit.Assert.assertSame("Result Isn't True ::", message1.equals(message2));
}
@Test
public void assertNull(){
// Declare first object
String message1 = null;
// Assert
org.junit.Assert.assertNull("Result Is Null ::", message1);
}
@Test
public void assertNotNull(){
// Declare first object
String message1 = "Hi World";
// Assert
org.junit.Assert.assertNull("Result Isn't True ::", message1);
}
}
Here’s below the result of execution as half of them failed cause the their respective assertions had failed also which will lead finally for whole Test class to be failed.
Notice that all failed assertions would have a resulted in error message that’s shown. This message is provided through assert(*) itself.
Little Bit About Hamcrest Library
You did see above how much Assert(*) method help you judge given equations and assert upon them to make up finally your Test Cases. These assertions aren’t just those provided by JUnit itself. Hamcrest library also makes an extension for JUnit and provide you another set of them (Let’s called them matchers)
This section would focus the light into most used of them and provide you the way in which they can be leveraged. Following below Table lists most of them:
And here’s below a provided sample that would use all of these matchers:
HamcrestTestCases.java
package com.journaldev;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.hamcrest.object.IsCompatibleType;
import org.junit.Test;
public class HamcrestTestCases {
@Test
public void testStartWith(){
// Create Employee instance
Employee employee = new Employee();
// Using assertThat to evaluate specific matcher
assertThat(employee.getName(), startsWith("Empty"));
}
@Test
public void testEndsWith(){
// Create Employee instance
Employee employee = new Employee();
// Using assertThat to evaluate specific matcher
assertThat(employee.getName(), endsWith("Name"));
}
@Test
public void testContainsWith(){
// Create Employee instance
Employee employee = new Employee();
// Using assertThat to evaluate specific matcher
assertThat(employee.getName(), containsString("y N"));
}
@Test
public void testEqualToIgnoringCase(){
// Create Employee instance
Employee employee = new Employee();
// Using assertThat to evaluate specific matcher
assertThat(employee.getName(), equalToIgnoringCase("eMpTy NaMe"));
}
@Test
public void testEqualToIgnoringWhiteSpace(){
// Create Employee instance
Employee employee = new Employee();
// Using assertThat to evaluate specific matcher
assertThat(employee.getName(), equalToIgnoringWhiteSpace(" Empty Name "));
}
@Test
public void testhasItem(){
// Create Employee instance
Employee employee = new Employee();
// Create employees list
List<Employee> employees = new ArrayList<Employee>();
// Add employee
employees.add(employee);
// Using assertThat to evaluate specific matcher
assertThat(employees,hasItem(employee));
}
@Test
public void testhasItems(){
// Create Employee instance
Employee employee1 = new Employee();
// Create Employee instance
Employee employee2 = new Employee();
// Create employees list
List<Employee> employees = new ArrayList<Employee>();
// Add employee
employees.add(employee1);
// Add employee
employees.add(employee2);
// Using assertThat to evaluate specific matcher
assertThat(employees,hasItems(employee1,employee2));
}
@Test
public void testhasEntry(){
// Create Employee instance
Employee employee1 = new Employee();
employee1.setName("Mohammad");
// Create a Map
HashMap<String,Employee> employees = new HashMap<String,Employee>();
// Add employee 1
employees.put(employee1.getName(), employee1);
// Assert
assertThat(employees, hasEntry(employee1.getName(), employee1));
}
@Test
public void testhasProperty(){
// Create Employee instance
Employee employee = new Employee();
// Assert
assertThat(employee, hasProperty("name"));
}
@Test
public void testNotNull(){
// Create Employee instance
Employee employee = new Employee();
// Assert
assertThat(employee, notNullValue());
}
@Test
public void testSameInstance(){
// Create employee
Employee employee = new Employee();
// Declare another employee variable
Employee employee2 = employee;
// Assert
assertThat(employee, sameInstance(employee2));
}
@Test
public void testInstanceOf(){
// Create employee
Employee employee = new Employee();
// Assert
assertThat(employee, instanceOf(Person.class));
}
@Test
public void testNotInstanceOf(){
// Create employee
Person person = new Person();
// Assert
assertThat(person, not(instanceOf(Employee.class)));
}
@Test
public void testIsCompatibleType(){
// Create isCompatible Matcher
IsCompatibleType<Person> isPersonCompatible = new IsCompatibleType<Person>(Person.class);
// Create isCompatible Matcher
IsCompatibleType<Employee> isEmployeeCompatible = new IsCompatibleType<Employee>(Employee.class);
// Assert; Employee class definition is compatible (instance) with/of Person
assertThat(Employee.class,isPersonCompatible);
// Assert; Person class definition is compatible (instance) with/of Person
assertThat(Person.class,isPersonCompatible);
// Assert; Person class definition is not compatible (instance) with/of Employee
assertThat(Person.class,not(isEmployeeCompatible));
}
@Test
public void testIsNotCompatibleType(){
// Create isCompatible Matcher
IsCompatibleType<String> isNotCompatible = new IsCompatibleType<String>(String.class);
// Assert; employee class definition isn't compatible/instance with/of String
assertThat(Employee.class,not(isNotCompatible));
}
@Test
public void testAnyOf(){
// Create isCompatible Matcher
IsCompatibleType<Person> isPersonCompatible = new IsCompatibleType<Person>(Person.class);
// Create isCompatible Matcher
IsCompatibleType<Employee> isEmployeeCompatible = new IsCompatibleType<Employee>(Employee.class);
// Assert; employee class is instance of Person OR employee
assertThat(Employee.class,anyOf(isPersonCompatible,isEmployeeCompatible));
}
@Test
public void testAllOf(){
// Create isCompatible Matcher
IsCompatibleType<Person> isPersonCompatible = new IsCompatibleType<Person>(Person.class);
// Create isCompatible Matcher
IsCompatibleType<Employee> isEmployeeCompatible = new IsCompatibleType<Employee>(Employee.class);
// Assert; Person class is an instance of Person AND not of Employee
assertThat(Person.class,allOf(isPersonCompatible,not(isEmployeeCompatible)));
}
}
class Person {
private String type;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
class Employee extends Person{
private int id = 0;
private String name = "Empty Name";
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Basically, JUnit framework doesn’t provide you that level of controlling the Hamcrest library do, so that it’s much better for you to combine both of them JUnit and Hamcrest to make sure that you are having reliable, specific and easy Test Cases.
Now, you can execute it by invoking CTRL + SHIFT + x + t to get the below result:
JUnit Extension – JWebUnit
JWebUnit is a framework built based on JUnit and it provides a way to write test cases for web applications testing purposes. Following sample shows you how it might be used for writing a test cases against the most simple HelloWorldPortlet
that was written previously in one of these tutorials provided for Apache Pluto Portal.
Using of Apache Pluto Portal would make writing the JWebUnit cases much more interesting as you should pass a login screen and navigate into your Portal pages before getting your HelloWorldPortlet
– Actually your web resource – examined.
Actually i did some minor modifications at the example that would be shown right here. This modifications get place to make sure JWebUnit is able to recognize some of components that are used.
HelloWorldPortlet.java
package com.journaldev.portlet;
import java.io.IOException;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.GenericPortlet;
import javax.portlet.PortletConfig;
import javax.portlet.PortletException;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
public class HelloWorldPortlet extends GenericPortlet {
private static int renderCount = 0;
private static int actionCount = 0;
public void doView(RenderRequest request, RenderResponse response)
throws PortletException, IOException {
synchronized(this){
renderCount++;
}
response.getWriter().print("<form id='main' action="+response.createActionURL()+">"
+ "<p>Render has executed "+renderCount+"</p>"
+ "<p>Action has executed "+actionCount+"</p>"
+ "<button id='submit' value="submit" type="submit">Submit</button>"
+ "</form>");
}
public void processAction(ActionRequest actionRequest, ActionResponse actionResponse){
synchronized(this){
actionCount++;
}
}
public void init( PortletConfig config ) throws PortletException {
super.init( config );
}
}
Here’s below hints for the component written above:
- HelloWorldPortlet is a simple Portlet resource that is responsible to show a simple form with ability to make a submission upon it.
- Accessing HelloWorldPortlet Portal page would increase the render counter by one.
- Submitting action button against HelloWorldPortlet would increase the action request by one.
Following below series of images would clarify you HelloWorldPortlet execution and business scenarios that you have to examine through JWebUnit.
- Access Apache Pluto Portal base url
https://10.10.90.3:8080/pluto
.
- Make sure you have modified
tomcat-users.xml
so that tomcat user is allowed to access and manage. - Enter tomcat as a username and password and submit login.
- Navigate into Apache Pluto Home page.
Portlet isn’t a standalone web resource, so that to make it accessible you should embed it inside a Portal page. We have created a HelloWorld Portal page and you’re able to do that by following the basic instructions in the referenced Apache Pluto tutorial above.
- Create a HelloWorld Portal page and add
HelloWorldPortlet
inside it.
- Initially, by each request on the HelloWorld Portal page, the
HelloWordlPortlet
would be rendered one more. In case you have copy the linkhttps://10.10.90.3:8080/pluto/portal/HelloWorld
once again and type it onto another Tab within the same browser, you would seeRender has executed 2
and so on. - Action request is the second type of request that Portlet supports. Portlet has two different request types in its lifecycle.
- To make sure you’re getting an action request, you should get Submit button clicked. That would also initiate another render request, so that you have to see Render has executed 2 and Action has executed 1.
Now, you have seen how HelloWorldPortlet
works against your actions that you did upon it. But what if you don’t want to process this directly into browser and want to execute this through using of JWebUnit.
In face and indeed, this automatic execution may lead you for a huge set of Test Cases that get running at every time you want, so that you will make sure your modifications, refinement and refactoring don’t break the basic functionality of your Portlet.
Following sample shows you a Test Case class that would get this scenario above examined:
HelloWorldPortletTestCase.java
package com.journaldev;
import net.sourceforge.jwebunit.junit.JWebUnit;
import org.junit.Before;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;
@FixMethodOrder(MethodSorters.JVM)
public class HelloWorldPortletTestCase {
@Before
public void prepareBaseURL(){
// Set base URL that JWebUnit will start from
JWebUnit.setBaseUrl("https://10.10.90.3:8080/pluto");
}
@Test
public void testBaseUrl(){
// Begin a conversation
JWebUnit.beginAt("/portal");
}
@Test
public void testShowingAndPopulatingLoginScreen(){
// Assert if login screen is displayed, so that username and password field would be shown
JWebUnit.assertTextFieldEquals("j_username", "");
JWebUnit.assertTextFieldEquals("j_password", "");
// Populating login screen with the required values
JWebUnit.setTextField("j_username", "tomcat");
JWebUnit.setTextField("j_password", "tomcat");
// Assert populating is done properly
JWebUnit.assertTextFieldEquals("j_username", "tomcat");
JWebUnit.assertTextFieldEquals("j_password", "tomcat");
// Login Into Portal
JWebUnit.clickButtonWithText("Login");
}
@Test
public void testNavigateIntoHelloWorldPortalPage(){
// Check if HelloWorld Portal page is exist or not
JWebUnit.assertLinkPresentWithText("HelloWorld");
}
@Test
public void testDoActualNavigationIntoHelloWorldPortalPage(){
// Navigate into HelloWorld Portal page
JWebUnit.clickLinkWithExactText("HelloWorld");
// Check of the Render has executed message
JWebUnit.assertTextPresent("Render has executed 1");
}
@Test
public void testInitiateActionRequestUponHelloWorldPortlet(){
// Check if the submit button is exist
JWebUnit.assertButtonPresent("submit");
// Click submit against HelloWorld Portlet
JWebUnit.clickButton("submit");
}
@Test
public void testMessagesAfterActionRequestUponHelloWorldPortlet(){
// Check of the Render has executed message
JWebUnit.assertTextPresent("Render has executed 2");
// Check of the Action has executed message
JWebUnit.assertTextPresent("Action has executed 1");
}
}
Here’s detailed information for code listed above:
- I have broke down above passed functional use case into multiple Test Cases.
- These Test Cases won’t be executed sequentially if you didn’t use
@FixMethodOrder(MethodSorters.JVM)
. As JUnit suppose that every @Test case is so dependent from another while the fact they’re not at least in our example. - Every functional case has examined while normal browser navigation is written at the above example as a Test case. Locate base URL, starting conversation, Showing and populating login screen, checking existence of
HelloWorld
Portal page, navigating into it, checking result of navigation, initiating Action request, checking whether the action request initiated is done properly. @FixMethodOrder
has been released since JUnit 4.11 release, so be careful from executing the same application using different release of JUnit rather than this mentioned in the pom file or one later.
Below is the result of execution above Test Cases; in case you don’t have this proper result, you can use JWebUnit.getPageSource()
that would consume returned HTML.
As you may noticed above, all Test Cases have been passed successfully and that means that we are able to have the same result that you did see while using the normal navigation against the browser.
Actually using JWebUnit against any Web resource, like Servlet, JSP, HTML and any resource that’s resulted in an HTML response would be much easier than using it against Apache Portal web application. To make sure we have had the most cases that should be covered, the given sample was within Apache Pluto Portal.
JUnit Extension – JSFUnit
Even that you may find a JSFUnit on the internet for JBoss, but it’s actually not a straight forward framework and you need some awareness for the core of it to make it used willingly.
Talking about JSF, means that you have a Servlet container that serves your application. And there’s a lot of components to be examined; Managed Beans, View IDs, expressions evaluation and many others. All of these components aren’t just plain Java classes, and thereby they need away to access it and specify their values easily.
At this section you’re going to use a container to make sure your Test Cases are running effectively, beside all of that, you’re going also to learn the most amazing JBoss’s framework which is used mainly for this purpose and it’s Arquillian.
Arquillian is a massive framework that can be used to write real Test Cases that adhere concept Test In Container for a Java Enterprise Edition.
Without any need for getting certain container up and running, you may configuring Arquillian to connect any container you want and then executing your Test Cases effectively.
For this purpose, I want to introduce you a way to assure that the JSF application referred here is executing properly and getting expected output without need for executing it on a Tomcat container.
That sample above is slightly modified, through using of faces-config.xml file rather using of JSF annotations. This is done like that to make sure the concept of Micro Deployment is so clear and for those who are using JSF 1.x.
Before getting started explaining a full example of how could Arquillian be used to achieve this mission, let’s look firstly at those assets your Arquillian Test Case should have:
- @RunWith that would refer for Arquillian Test Runner.
- Public static method that’s annotated with @Deployment.
- At least one method annotated with @Test.
Take into consideration as well:
- Using latest version of Arquillian JSF Unit Integration.
- Using Tomcat 7.
- Using of JDK 1.6.
First and foremost, let’s have a fast look at every component Arquillian framework has used:
- @Deployment: is a mandatory method for tests that run inside a container to generate the Archive deployment (Micro Deployment); Java Archive (JAR), Web Archive (WAR) and Enterprise Archive (EAR). This archive deployment has been prepared by ShrinkWrap.
ShrinkWrap is a Java API for creating archives (jar, war and ear) in Java. By using ShrinkWrap, you’re focusing on your Test Cases, by bringing all required libraries instead of bring all of them. As you may see below within the sample, no need to include all libraries within your Archive.
- @RunWith: is discussed previously, as it’s used to mark different Test Runner to be used. With Arquillian framework, you must annotate your Test Cases using it to make sure you’re getting it executing properly.
If you do revert back into sample mentioned, you should see it’s so simple JSF application as it contains:
- Simple helloWorld.xhtml web resource.
- Simple faces-config.xml that’s contained one Managed Bean defined.
- Simple web XML file.
- Simple Managed Bean that’s contained one attribute called s1.
- JSF implementation and API libraries.
- JSTL library.
The same sample would be used here except as we mentioned using of faces-config.xml rather using its annotations.
Now, look below at the Arquillian Test Class followed with the required libraries inside your pom file:
ArquillianHelloWorldTestCase.java
package com.journaldev;
import java.io.File;
import java.io.IOException;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.jsfunit.api.InitialPage;
import org.jboss.jsfunit.jsfsession.JSFClientSession;
import org.jboss.jsfunit.jsfsession.JSFServerSession;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(Arquillian.class)
public class ArquillianHelloWorldTestCase {
@Deployment
public static WebArchive createDeployment() {
// Create a WAR (Micro deployment) with a given name called
// helloworld.war
WebArchive webArchive = ShrinkWrap.create(WebArchive.class,
"helloworld.war");
// Set web.xml inside created micro WAR
webArchive.setWebXML(new File("src/main/webapp/WEB-INF/web.xml"));
// Add classes
webArchive.addPackage("com.journaldev.jsf.helloworld");
// Add web resource
webArchive.addAsWebResource(new File("src/main/webapp","helloWorld.xhtml"));
// Add faces-config.xml as a web-inf resource
webArchive.addAsWebInfResource(new File("src/main/webapp/WEB-INF/faces-config.xml"),"faces-config.xml");
// Add required libraries
webArchive.addAsLibrary(new File("C:/Users/mohammad.amr/.m2/repository/com/sun/faces/jsf-impl/2.1.13/jsf-impl-2.1.13.jar"));
webArchive.addAsLibrary(new File("C:/Users/mohammad.amr/.m2/repository/com/sun/faces/jsf-api/2.1.13/jsf-api-2.1.13.jar"));
webArchive.addAsLibrary(new File("C:/Users/mohammad.amr/.m2/repository/jstl/jstl/1.2/jstl-1.2.jar"));
// return the deployment
return webArchive;
}
@Test
@InitialPage("/faces/helloWorld.xhtml")
public void testInitialPage(JSFServerSession server, JSFClientSession client)
throws IOException {
// Test navigation to initial viewID
Assert.assertEquals("/helloWorld.xhtml", server.getCurrentViewID());
}
@Test
@InitialPage("/faces/helloWorld.xhtml")
public void testHelloWorldBeanNotNull(JSFServerSession server, JSFClientSession client){
// Test if Managed Bean is null
Assert.assertNotNull(server.getFacesContext().getExternalContext().getSessionMap().get("helloWorld"));
}
@Test
@InitialPage("/faces/helloWorld.xhtml")
public void testS1Value(JSFServerSession server, JSFClientSession client){
// Test if Managed Bean is null
Assert.assertEquals("Hello World!!",server.getManagedBeanValue("#{helloWorld.s1}"));
}
}
pom.xml
<?xml version="1.0"?>
<project
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>com.journaldev</groupId>
<artifactId>HelloWorldTestCase</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>HelloWorldTestCase</name>
<url>https://maven.apache.org</url>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.17</version>
</plugin>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- HTML Unit library -->
<dependency>
<groupId>net.sourceforge.htmlunit</groupId>
<artifactId>htmlunit</artifactId>
<version>2.8</version>
</dependency>
<!-- JUnit Library -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!-- Hamcrest Library -->
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<version>1.3</version>
</dependency>
<!-- JWebUnit Library -->
<dependency>
<groupId>net.sourceforge.jwebunit</groupId>
<artifactId>jwebunit-htmlunit-plugin</artifactId>
<version>3.0</version>
</dependency>
<!-- Arquillian JUnit container library -->
<dependency>
<groupId>org.jboss.arquillian.junit</groupId>
<artifactId>arquillian-junit-container</artifactId>
<version>1.1.8.Final</version>
</dependency>
<!-- Arquillian Tomcat Container that's used for Arquillian.xml -->
<dependency>
<groupId>org.jboss.arquillian.container</groupId>
<artifactId>arquillian-tomcat-remote-7</artifactId>
<version>1.0.0.CR7</version>
</dependency>
<!-- JSF Implementation And API -->
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-api</artifactId>
<version>2.1.13</version>
</dependency>
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-impl</artifactId>
<version>2.1.13</version>
</dependency>
<!-- Servlet API -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<!-- JSTL API -->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- Arquillian JUnit Library -->
<dependency>
<groupId>org.jboss.jsfunit</groupId>
<artifactId>jsfunit-arquillian</artifactId>
<version>2.0.0.Beta2</version>
</dependency>
<!-- Arquillian JUnit Core library -->
<dependency>
<groupId>org.jboss.jsfunit</groupId>
<artifactId>jboss-jsfunit-core</artifactId>
<version>2.0.0.Beta2</version>
</dependency>
<!-- ShrinkWrap Libraries -->
<dependency>
<groupId>org.jboss.shrinkwrap</groupId>
<artifactId>shrinkwrap-api</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>org.jboss.shrinkwrap.resolver</groupId>
<artifactId>shrinkwrap-resolver-api</artifactId>
<version>2.2.0-beta-2</version>
</dependency>
<dependency>
<groupId>org.jboss.shrinkwrap.resolver</groupId>
<artifactId>shrinkwrap-resolver-impl-maven</artifactId>
<version>2.2.0-beta-2</version>
</dependency>
<dependency>
<groupId>org.jboss.shrinkwrap.descriptors</groupId>
<artifactId>shrinkwrap-descriptors-api</artifactId>
<version>1.0.0-beta-1</version>
</dependency>
<dependency>
<groupId>org.jboss.shrinkwrap.descriptors</groupId>
<artifactId>shrinkwrap-descriptors-impl</artifactId>
<version>1.0.0-beta-1</version>
</dependency>
</dependencies>
</project>
Here’s detailed explanation for code listed above:
- You’ve created one Test Class called
ArquillianHelloWorldTestCase.java
. - This class contains one mandatory
@Deployment
method as its Test Cases have required a container (Servlet container). @Deployment
method have returned a Web Archive.- Web Archive returned has contained one Web XML resource, one package, one web resource, one
faces-config.xml
and three required libraries; JSF implementation and the JSTL. Those resources have been mentioned explicitly so that the Web Archive would contain them accordingly once @Deployment finishes execution. - If you didn’t bind a name for your Web Archive, so it would be binded randomly with a given name by the
ShrinkWrap
implementation. Deployment name ishelloworld.war
. @Deployment
will communicate with your (Running Tomcat 7) so that the deployment would be installed there ashelloworld.war
.- Once the deployment is published successfully, your Test Cases execution would be started.
- All Test Cases methods have mentioned two parameters;
JSFServerSession
andJSFClientSession
which are injected automatically by Arquillian framework. - All Test Cases methods have assumed the initial page that would be requested and do the Test Case upon it is
/faces/helloWorld.xhtml
which uses afacelets
implementation to render the UI component. - Passing assertions inside these methods would mark them passed with a green light. Else, the failure and its message would be there.
- TestInitialPage would examine if the rendered JSF view has the /helloWorld.xhtml as a view ID.
- TestHelloWorldBeanNotNull would examine if the HelloWorld bean is injected by the JSF framework or not.
- TestS1Value would examine if the value of attribute
s1
is equal to Hello World!! or not.
To make sure you have the ability to run above sample you should check on the below:
- Your Tomcat 7 is up and Running.
- Your source paths or resources (src/main/resources) have mentioned an Arquillian container configuration
arquillian.xml
which will use the JMX to connect your Tomcat.
arquillian.xml
<arquillian xmlns="https://jboss.org/schema/arquillian"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
https://jboss.org/schema/arquillian
https://jboss.org/schema/arquillian/arquillian_1_0.xsd">
<container qualifier="tomcat-remote-7" default="true">
<configuration>
<property name="user">tomcat</property>
<property name="pass">tomcat</property>
</configuration>
</container>
</arquillian>
- Make sure your Tomcat configuration has allowed JMX connection with your Tomcat. This might be done by adding the below line into your
JAVA_OPTS
variable within your catalina.bat
New JAVA_OPTS
set JAVA_OPTS=%JAVA_OPTS% %LOGGING_CONFIG% -Dcom.sun.management.jmxremote.port=8089 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false
- Allow Tomcat user to has manage-script role as it would be used for executing deployment command.
tomcat-users.xml
<tomcat-users>
<role rolename="tomcat"/>
<role rolename="manager-gui"/>
<role rolename="manager-script"/>
<user username="tomcat" password="tomcat" roles="tomcat,manager-gui,manager-script"/>
</tomcat-users>
If you get this sample executed through invoking CTRL + SHIFT + x + t you would see:
As you can see from the execution of sample above, all cases have been executed and passed successfully while the process of deployment and Test Cases examinations have been done through Arquillian JSF Unit framework.
Once your Test Cases get executed and the result of execution being shown, the deployment is removed from Tomcat webapps directory.
Sometime this removal wasn’t safe, so the exploded folder of your deployment is still there while the WAR is removed. There, you need to stop your Tomcat and remove it by yourself or your make sure using context.xml with antiJARLocking facility.
Maven & JUnit
As most of developers know, Maven is a build tool that is used for building, compiling, packaging and managing dependencies of your Application. Even it’s a build and dependency tool but it also helps providing a way to execute your Test Cases through a built-in life cycle.
By using mvn test
you’re driving your Maven tool to execute your Test Cases that are located beneath your src/test/java
.
For this purpose, i have copied all created Test Cases above and achieved some minor modifications that would lead those Test Cases to be run effectively while Maven running. These slight modifications were:
- Add
maven-surefire-report-plugin
that would be used for reporting all results for your Test Cases execution. - Increase timeout period in
HelloWorldTestCase.java
. - Modifying
testNullPointerExceptionShouldBeRaised
inside the same above class to throw it each time this method has called with. - Create a new package under
src/test/java
and copy all Test Classes into it.
The structure of the application would look like below:
Due to different Test Cases that we have and being both of Apache 7 & Apache Pluto servers have been used and they should be up and running to get these Test Cases executed properly; i have modified the Tomcat ports from Eclipse itself for Apache 7.
Once you’re executing mvn test
you should see your Test Cases had written being executed and the result would be shown on both of console and under your Target folder target/surefire-reports
.
Before executing your Test Cases, make sure you have your Apache Pluto and Apache Tomcat 7 up and running so that Arquillian and Portlet Test Cases get executed properly.
The result of execution that you would get it will be:
As you may notice, Maven has executed its Test phase and gets all Test Cases that are defined beneath the src/test/java
executed successfully.
This is not the way in which you may know exactly what happens with your Test Case. Beside console messages you have also ability to access the target/surefire-reports
folder which will contain set of files that show you execution output that are resulted in by your Test Cases.
Let’s see the result of execution Arquillian Test Case:
Summary
JUnit framework is an open source framework that’s used for executing set of Test Cases. While Testing phase takes different forms; Acceptance Test, Integration Test, Functional Test and Unit Test; the most important one of them is Unit Test that would examine your components individually to make sure they’re working properly.
Test coverage of functional Test doesn’t exceed 70% according for most QA philosopher, while Unit Test would cover all cases that might not be examined while normal functional Test.
If you combine your Unit Test with Integration, you’re likely about getting full fledged application that’s mostly clean.
According for different forms of technologies and components were provided these days, it’s so important to use reliable tools and APIs to get these components Tested. Presence of JUnit, JWebUnit, JSF Unit and much more would help you achieve this mission.
This tutorial is aimed to provide you a massive amount of information about most of these frameworks a along side with deep clarification for JUnit 4. Contribute us by commenting below and find below implemented sample for your download.