JUnit

JUnit Docs

JUnit is a Regression Testing Framework used by developers to implement unit testing in Java. (Adv)That is useful for accelerate programming speed and increase the quality of code.

Features

JUnit test framework provides following important features

  • Fixtures

  • Test suites

  • Test runners

  • JUnit classes

Fixtures

A test fixture is a fixed state of a set of objects used as a baseline for running tests. The purpose of a test fixture is to ensure that there is a well known and fixed environment in which tests are run so that results are repeatable. Examples of fixtures:

  • Loading a database with a specific, known set of data

  • Copying a specific known set of files

  • Preparation of input data and setup/creation of fake or mock objects

In other word, creating a test fixture is to create a set of objects initialized to certain states to complete test.

Type of Fixture

 

There are four fixture annotations: two for class-level fixtures and two for method-level ones. At the class level, you have @BeforeClass and @AfterClass, and at the method (or test) level, you have@Before and @After.

 

If a group of tests requires diferent test fixtures, you can write code inside the test method to create its own test fixture. (or Use Method level Fixture)

If a group of tests shares the same fixtures, you should write a separate setup code to create the common test fixture. ( or Use Class level Fixture)

Advantage

  1. you have two or more tests for a common set of objects. Using a test fixture avoids duplicating the code necessary to initialize (and cleanup) the common objects. (Code Reusablity)

  2. the objects (variables) in a test fixture, with each test invoking different methods on objects in the fixture and asserting different expected results. Each test runs in its own test fixture to isolate tests from the changes made by other tests. That is, tests don't share the state of objects in the test fixture. Because the tests are isolated, they can be run in any order. (to resolve this using TestSuits)

To create a test fixture, declare instance variables for the common objects. Initialize these objects in a public void method annotated with@Before. The JUnit framework automatically invokes any @Before methods before each test is run.

Adding Fixtures

Now, let's consider the case in which each of the tests that you design needs a common set of objects. One approach can be to create those objects in each of the methods. Alternatively, the JUnit framework provides two special methods, setUp() and tearDown() when extends TestCase, to initialize and clean up any common objects. But when we extends, we create tight coupling with JUnit and over application due to this Annotation are comes. It is create loose coupling environment.

 

This avoids duplicating the test code necessary to do the common setup and cleanup tasks. These are together referred to as fixtures. The framework calls the setup() before and tearDown()after each test method—thereby ensuring that there are no side effects from one test run to the next. This also implies that there is no fixed order in which the framework may execute the test methods during a run of the test runner. So in all cases, avoid temporal coupling of the tests. If however, it is necessary to perform the tests in some specific order, we can use the static suite() method to ensure the ordering. For example, you can expect that the tests below would be executed in the order indicated.

//define a test suite – ensure the order of the tests
public static Test suite() {
    TestSuite testsToRun = new TestSuite();
    testsToRun.addTest(new MyTest("testFirstMethod"));
    testsToRun.addTest(new MyTest("testSecondMethod"));
   return testsToRun
 }


One important thing to remember is that one should not use the TestCase constructor for any of the setup code, as shown in the code below. Any exception to the setup code will simply be reported as an AssertonFailedError by the framework, and the resulting stack trace will not be very helpful for the developer.

// extend the TestCase class
public class MyTest extends TestCase {

//pass the name of the test to the super class
 public MyTest(String name) {
   super(name);
// place the setup code here – Bad Idea!
 }

Test suites

First we understand meaning of suits: Suits is a collection of matching things.  If you are going to hotel and you book suite for two person than it means you book two room which is internally connected that is called suite.


So If you want to test some class and you want to test couple of methods who share (connect) object for that we required suite.

Suite have two important information:

  • Which test classes are include

  • Order of test execution

 

Room Object is shared by three methods of Single Class or different class. But with if isDoorOpen = false then isClean() and hasStudyTable() always return false. Because if room is lock then how to know it is clean or has table. So that’s why some time order of execution of test is also important. For that in suites we define order of method also. So first we call open() i.e. change Room isDoorOpen state to true then we call isClean() then its properly do functional test.

Probably one of the best known processors is the Suite. It allows to run collections of tests and/or other suites in a hierarchically or thematically structured way. Note that the specifying class itself has usually no body implementation . It is annotated with a list of test classes, that get executed by running the suite:


However the structuring capabilities of suites are somewhat limited. Because of this JUnit 4.8 introduced the lesser known Categories concept. This makes it possible to define custom category types like unit-, integration- and acceptance tests for example. To assign a test case or a method to one of those categories the Category annotation is provided:

 

With Categories annotated classes define suites that run only those tests of the class list, that match the specified categories. Specification is done via include and/or exclude annotations.

 

Test runner

JUnit supports the usage of various types of test processors for this purpose. Thus it delegates at runtime test class instantiation, test execution and result reporting to such processors, which have to be sub types of org.junit.Runner.

A test case can specify its expected runner type with the @RunWith annotation. If no type is specified the runtime chooses BlockJUnit4ClassRunner as default. Which is responsible that each test runs with a fresh test instance and invokes lifecycle methods like implicit setup or teardown handlers (see also the chapter about Test Structure).

what is a JUnit Runner?

A JUnit Runner is class that extends JUnit's abstract Runner class. Runners are used for running test classes. The Runner that should be used to run a test can be set using the @RunWith annotation.

JUnit tests are started using the JUnitCore class. This can either be done by running it from command line or using one of its various run() methods (this is what your IDE does for you if you press the run test button).

JUnitCore then uses reflection to find an appropriate Runner for the passed test classes. One step here is to look for a @RunWithannotation on the test class. If no other Runner is found the default runner (BlockJUnit4ClassRunner) will be used. The Runner will be instantiated and the test class will be passed to the Runner. Now it is Job of the Runner to instantiate and run the passed test class.

How do JUnit Runners work?

Lets look at the class hierarchy of standard JUnit Runners:

 

Runner is a very simple class that implements the Describable interface and has two abstract methods:

The method getDescription() is inherited from Describable and has to return a Description. Descriptions contain the information that is later being exported and used by various tools. For example, your IDE might use this information to display the test results.

run() is a very generic method that runs something (e.g. a test class or a test suite).

I think usually Runner is not the class you want to extend (it is just too generous).

In ParentRunner things get a bit more specific. ParentRunner is an abstract base class for Runners that have multiple children. It is important to understand here, that tests are structured and executed in a hierarchical order (think of a tree).

For example: You might run a test suite which contains other test suites. These test suites then might contain multiple test classes. And finally each test class can contain multiple test methods.

ParentRunner has the following three abstract methods:

Subclasses need to return a list of the generic type T in getChildren(). ParentRunner then asks the subclass to create a Description for each child (describeChild()) and finally to run each child (runChild()).

Now let's look at two standard ParentRunners: BlockJUnit4ClassRunner and Suite.

BlockJUnit4ClassRunner is the default Runner that is used if no other Runner is provided. So this is the Runner that is typically used if you run a single test class. If you look at the source of BlockJUnit4ClassRunner you will see something like this:

Of course this is overly simplified, but it shows what is essentially done in BlockJUnit4ClassRunner.

The generic type parameter FrameworkMethod is basically a wrapper around java.lang.reflect.Method providing some convenience methods. In getChildren() the test class is scanned for methods annotated with @Test using reflection. The found methods are wrapped in FrameworkMethod objects and returned. describeChildren() creates a Description from the method name and runChild() finally runs the test method. BlockJUnit4ClassRunner uses a lot of protected methods internally. Depending on what you want to do exactly, it can be a good idea to check BlockJUnit4ClassRunner for methods you can override. You can have a look at the source of BlockJUnit4ClassRunner on GitHub.

The Suite Runner is used to create test suites. Suites are collections of tests (or other suites). A simple suite definition looks like this:

A test suite is created by selecting the Suite Runner with the @RunWith annotation. If you look at the implementation of Suiteyou will see that it is actually very simple. The only thing Suite does, is to create Runner instances from the classes defined using the @SuiteClasses annotation. So getChildren() returns a list of Runners and runChild() delegates the execution to the corresponding runner.

JUnit Classes

There are three important classes to write JUnit cases

  • Assert which contain a set of assert methods.

  • TestCase which contain a test case defines the fixture to run multiple tests.

  • TestResult which contain methods to collect the results of executing a test case.

Assert

A set of assertion methods useful for writing tests. Only failed assertions are recorded. These methods can be used directly: Assert.assertEquals(...), however, they read better if they are referenced through static import:

import static org.junit.Assert.*;
   ...
   assertEquals(...);

TestCase

A test case defines the fixture to run multiple tests. To define a test case

1) implement a subclass of TestCase

2) define instance variables that store the state of the fixture

3) initialize the fixture state by overriding setUp

4) clean-up after a test by overriding tearDown.

Each test runs in its own fixture so there can be no side effects among test runs. Here is an example:

public class MathTest extends TestCase {
    protected double fValue1;
    protected double fValue2;

   protected void setUp() {
        fValue1= 2.0;
        fValue2= 3.0;
    }
}

For each test implement a method which interacts with the fixture. Verify the expected results with assertions specified by calling assertTrue with a boolean.

  public void testAdd() {
       double result= fValue1 + fValue2;
       assertTrue(result == 5.0);
   }

Once the methods are defined you can run them. The framework supports both a static type safe and more dynamic way to run a test. In the static way you override the runTest method and define the method to be invoked. A convenient way to do so is with an anonymous inner class.

TestCase test= new MathTest("add") {
       public void runTest() {
           testAdd();
       }
};
test.run();

The dynamic way uses reflection to implement runTest. It dynamically finds and invokes a method. In this case the name of the test case has to correspond to the test method to be run.

TestCase test = new MathTest("testAdd");
test.run();

The tests to be run can be collected into a TestSuite. JUnit provides different test runners which can run a test suite and collect the results. A test runner either expects a static method suite as the entry point to get a test to run or it will extract the suite automatically.

public static Test suite() {
     suite.addTest(new MathTest("testAdd"));
     suite.addTest(new MathTest("testDivideByZero"));
     return suite;
 }

 

TestResult

 

Problems that we are facing in testing the applications

If we want to test any application, In standalone, we need to call the respective method’s main() method but there are so many problems in testing the flow using main() method.

In a web application, to test the flow we need to deploy it in the server so if there is a change then again we need to restart the server. Here also facing problems while testing the application.

  • Writing main method checks is convenient because all Java IDEs provide the ability to compile and run the class in the current buffer, and certainly have their place for exercising an object’s capability. There are, however, some issues with this approach that make it ineffective as a comprehensive test framework:

  • There is no explicit concept of a test passing or failing. Typically, the program outputs messages simply with System.out.println; the user has to look at this and decide if it is correct.

  • main has access to protected and private members and methods. While you may want to test the inner workings of a class may be desired, many tests are really about testing an object’s interface to the outside world.

  • There is no mechanism to collect results in a structured fashion.

  • There is no replicability. After each test run, a person has to examine and interpret the results.

  • The JUnit framework addresses these issues, and more

Advantages of JUnit

  • JUnit addresses the above issues, It’s used to test an existing class. Suppose, If we have Calculation class then, we need to write CalculationTest to test the Calculation class.

  • Using JUnit we can save testing time.

  • In real time, in the web application development we implement JUnit test cases in the DAO classes. DAO classes can be tested with out server.

  • With JUnit we can also test Struts / Spring applications but most of the time we test only DAO classes. Even some times service classes also tested using JUnit.

  • Using JUnit, If we want to test the application (for web applications) then server is not required so the testing becomes fast.

 

Automatically create JUnit test

Free tools:

  • CodePlex AnalytiX used to be a commercial tool (it was the first commercial plugin for Eclipse back in 2001), but since Google bought the company developing it, the product has been released as free. It's a full IDE based on Eclipse and a finalist of Jolt Award in test generation at 2007. The features are nice, but the tool hasn't been updated in long time, so it unfortunately doesn't work with current versions of eclipse, and seems to have problems with code requiring java >= 1.5.

  • EvoSuite is a a winner of SBST (Search-Based Software Testing) '13 unit test generation competition. There exists an Eclipse plugin, web interface and command line version of the tool. There is a regression criteria documented, but apparently it doesn't work yet - the tests generated target for branch coverage, weak mutation coverage or strong mutation coverage.

  • Randoop uses feedback-directed random test generation approach. The tool has been around since 2007 and has been in continuous development. Randoop can produce both regression tests and error-finding tests. It's a robust and reliable command line tool, and Eclipse plugin exists as well.

  • Palus claims to use both dynamic and static analysis, and is building on top of Randoop. Its authors claim that it has been used internally at Google. My experience with this software is that at least the current version (0.2) seems to have some internal issues and it doesn't seem to scale up well.

  • Daikon, Eclat, Javalanche, Java PathFinder, JCrasher, jWalk, Korat, RecGen and ReCrash are free tools that are available as well.

I use the Eclipse plugin MoreUnit. It can generate TestClasses and test-methods. It also shows which methods have test methods ...

Together with TestNG(JUnit is also good) and EclEmma junit testing is quite easy to handle and keep track on the code coverage

要查看或添加评论,请登录

Javed Mulla的更多文章

  • Dynamic Programming

    Dynamic Programming

    Dynamic Programming: DP is an algorithm's technique which is usually based on a formula executed recently and one…

    2 条评论
  • Performance

    Performance

    p1

  • Servlet Life Cycle

    Servlet Life Cycle

    Servlet Life Cycle Describe the purpose and event sequence of the servlet life cycle: (1) servlet class loading, (2)…

    1 条评论
  • Decorate Design Pattern

    Decorate Design Pattern

    WHY required ? Let's assume you are looking for a girlfriend. You want a girl with different qualities.

    2 条评论
  • JSF life cycle

    JSF life cycle

    JSF life cycle

  • Servlet to Servlet communication & Threading

    Servlet to Servlet communication & Threading

    Servlet

  • Spring core

    Spring core

    IOC is heart of Spring framework. We are divided spring application into three logical parts.

  • DI and IOC

    DI and IOC

    DI and IOC Using the DI is to way of getting the decoupling in java. Using the DI we are not create/instantiate the…

    1 条评论
  • Logical Question 3

    Logical Question 3

    you have a set of integers between 1 ..

    3 条评论
  • Logical Question 2

    Logical Question 2

    n the party everyone do handshake with the one another. So total 66 handshake are done.

社区洞察

其他会员也浏览了