JUnit Introduction

 

JUnit Introduction

Preface

Tow months ago, I promised my teammates to write an essay about how to use JUnit. It takes me a long time to think about this essay.  It is easy to use JUnit, but it is difficult to find the whole world of JUnit. There are too many methods, patterns, theories about software development in the back of JUnit.

 

Finally, I decide to merely introduce JUnit to all of my classmates in this essay.  In the later essays we can discuss other topics such as TDD (Test-Driven Development), IOC (Inversion of Control) and so on.

 

The first chapter of this essay introduces how to use JUnit separately, how to use it in Eclipse.

 

The second chapter introduces how to coding with JUnit for a developer.

 

The third chapter introduces the benefits from JUnit

 

The forth chapter introduces some best practices of coding with JUnit.

Introduction

What’s JUnit

 

There is a very concise definition for JUnit on www.junit.org site,

 

JUnit is a regression testing framework written by Erich Gamma and Kent Beck. It is used by the developer who implements unit tests in Java.

 

JUnit is a Unit Testing Framework for Java. The core features of JUnit are,

1.       Write Unit Test Case Easily and Elegantly,

2.       Do Regression Test Automatically,

3.       Do Regression Test Repetitiously

 

A Simple Example

 

Below is a simple calculator,

package ery.junit.example;

 

/**

 * This is a simple caculator.

 */

public class Calc {

       private Calc() {}   

       public static int add(int a, int b) {

              return a + b;

       }    

       public static int subtract(int a, int b) {

              return a - b;

       }

}

 

Below is the test class for this calculator,

package ery.junit.example;

import junit.framework.TestCase;

import junit.swingui.TestRunner;

 

/**

 * This is the test class for <code>Calc</code>.

 */

public class CalcTest extends TestCase {

 

       public void testAdd() {

              int expact = 10;

              int sum = Calc.add(2, 8);

              assertEquals(expact, sum);

       }

 

       public void testSubtract() {

              int expact = 6;

              int dif = Calc.subtract(8, 2);

              assertEquals(expact, dif);

       }

      

       public static void main(String[] args) {

              TestRunner.run(CalcTest.class);

       }

}

 

Run the test class as a “JUnit Test” in Eclipse, JUnit view will be shown to display the test results,

 

 

Run the test class as “Java Application” in Eclipse, A Swing GUI provided by JUnit will be shown to display the test results,

 

As you have seen if all your test cases passed, the GUI will show a green progress bar; otherwise, a red one will be shown.

 

The world view of JUnit is, “Keep the bar green and keep the code clean”.

 

TestCase - Expectation and Result

 

In the example above, we write a test class for Cacl.class.  A test class should inherit “junit.framework.TestCase” and implement some “public void test*()” methods.

 

Though CalcTest.class inherits “junit.framework.TestCase”, its instance is not a Test Case. JUnit framework will use java reflection mechanism to discover all “test*()” methods and create a Test Case instance for each method. So in the example above, CalcTest.class defines two Test Cases, one is “testSubtract”, the other is “testAdd”.

 

A Test Case is an atomic unit of the whole test suite. What a test case does is simply to compare Expectation and Result.

 

For example, in our “testAdd” case, we define our expected “sum” first and then call the “Calc.add” method to do addition operation. Finally, we assert the “sum” we got feeds our Expectation. This is the pattern we code a Test Case.

 

TestCase – Setup and TearDown

 

In most circumstances, we have to set up some context for a test case before it starts to run, and tear down the context to restore the initial state after it ends.

 

In JUnit framework, we override “setUp” and “tearDown” method of “junit.framework.TestCase “to set up and tear down context of a test case.

 

An example from NM4000 TFTP Tool,

 

package com.unknown.broadband.cft.dirparser;

 

import java.io.File;

import java.net.URL;

import com.unknown.broadband.cft.RemoteTestCase;

import com.unknown.broadband.cft.unit.IMutableUnit;

import com.unknown.broadband.cft.unit.impl.NodeFile;

import com.unknown.broadband.cft.unit.impl.NodeFileUnit;

import com.unknown.broadband.cft.unit.impl.NodeLoadPara;

 

public class FlashDirParserTestCase extends RemoteTestCase {

 

       private URL url;

 

       /* (non-Javadoc)

        * @see junit.framework.TestCase#setUp()

        */

       protected void setUp() throws Exception {

              super.setUp();

              String path = RemoteTestCase.class.getPackage().getName();

              path = path.replace('.', File.separatorChar);

              path += File.separator + bundle.getString("flash.dir");

              url = ClassLoader.getSystemResource(path);

              System.out.println(url);

       }

 

       public void testParseDir() {

              IMutableUnit root = new NodeFileUnit(new NodeFile("/"), new NodeLoadPara("/", 69));

              try {

                     DirParserFactory.createFlashDirParser().parseDir(url.getFile(), root);

                     IMutableUnit flash = root.getChild("flash");

                     assertNotNull(flash);

                     IMutableUnit boot = flash.getChild("boot");

                     assertNotNull(boot);

              } catch (DirParseException e) {

                     e.printStackTrace();

                     assertFalse(true);

              }

       }

 

       protected void tearDown() throws Exception {

              super.tearDown();

       }

}

 

This is a test class for FlashDirParser.class in TFTP Tool. We intend to verify whether a parser can work well. Before the test case “testParseDir” starts to run, we have to load “flash.dir” file first. We do it by override “setUp()” method.

 

Call sequence for the test case above is, setUp()àtestParseDir ()àtearDown(). This call pattern will ensure each test case runs isolate in its own context. This is an important factor to a unit test framework.

 

TestSuite – Group Test Cases

 

There are often many test classes and test cases for a project. We have to group them together and provide one entry to run all of them. JUnit provides “junit.framework.TestSuite” class to support this feature.

 

An example from TFTP Tool,

package com.unknown.broadband.cft.dirparser;

import junit.framework.Test;

import junit.framework.TestSuite;

 

public class AllDirParserTest {

 

    public static Test suite() {

        TestSuite suite = new TestSuite(

                "Test for com.unknown.broadband.cft.dirparser");

        //$JUnit-BEGIN$

        suite.addTestSuite(FlashDirParserTestCase.class);

        suite.addTestSuite(ICMDirParserTestCase.class);

        suite.addTestSuite(RootDirParserTestCase.class);

        suite.addTestSuite(HZDirParserTestCase.class);

        //$JUnit-END$

        return suite;

    }

}

 

Pattern of create a test suite is as following,

 

1.       Create a class and define a public static method named “suite” without arguments.

2.       In method “suite”, create a “junit.framework.TestSuite” instance first, and then add other test suite to it.

3.       Return the “suite” as a Test instance.

 

Run the test suite in Eclipse, there will be a Test Case Tree in JUnit View,

 

In this chapter I just introduce how to use JUnit briefly. You can find plenty docs, articles and examples on www.junit.org site for further learning. Next chapter will introduce the develop pattern worked with JUnit.

 

Coding with JUnit

Coding Pattern - Coding and Debug

 

The traditional coding pattern is often, we write a big block of code, and then run it and check whether it works well. In the most of time, it can’t, so we begin to debug it until it seems to work.

 

There are some problems with this pattern. First, we often release a big piece of “opaque” code with many bugs; second, with size of your code increases, you will take more time to do debug but not coding.

 

Sometimes we maybe write a “main” method in each class to do some simple tests. But it is bad and far away enough, I think. First, we mix test code with runtime code and may often add some unnecessary dependency to the class you test; second, we cannot test automatically, we have to run each “main” manually; third, we cannot test continuously, we cannot run all these “main” tests before each release; fifth, we often test many routines in one “main” method, so we cannot setup an independent context for each test case.

 

Coding Pattern - Coding, Test, Coding and Test…

 

Work with JUnit, the coding pattern is a coding and test circle. We write a small piece of code, and then write a few test cases for that code; if all the test cases passed, we write more code, and then we write more test cases. Finally, there are two type of source code, one is runtime code, and the other is test code. In each release, we build the runtime code first, and then build the test code and run all test cases automatically.

 

Consequences of applying this pattern are, first, we produce “apparent” code with fewer bugs than “opaque” code; second, we can test automatically and continuously, we can ensure we do not break something in each release; third, we will become more productive for we need not consume much time to debug the whole system.

 

One may say that it takes much time to write test code. Yeah, it takes time. But I bet that it will be not longer than the time you consume to do debug. The core reason we do not like to write test code is that it is difficult to change our coding habit.

 

Coding Pattern - Test, Coding, Test and Coding…

 

There is a more extreme coding pattern worked with JUnit which is named with TDD (Test-Driven Development).  On the contrary to the pattern above, the coding and test circle is, we write some test cases according to requirements first, and then write code to make the cases pass; in turn, we write more test cases, and then write more code.

 

I just read some articles and books about this pattern but never try it. But many mentors in software development field are trying to use this pattern to write code. Value of this pattern is first it can drive out the real requirements to a software system; second, it can produce a simple, elegant, flexible design.

 

We have much to learn for this pattern.  It is also difficult for us to apply this pattern to our NMS project.

 

Coding with JUnit in Eclipse

 

Eclipse integrates JUnit as a core feature of JDT (Java Development Tool). It is very easy to apply the “Coding, Test, Coding, and Test ...” pattern in Eclipse IDE.

 

In our first example of this essay, I write the Calc.class and then generate the test class with new “JUnit Test Case” wizard in Eclipse.

 

We select to new a “JUnit Test Case” in first wizard page,

 

Input the test class name and the tested class in the second wizard page,

 

Then you can select the methods you want to test in the third wizard page,

 

Ok, click “Finish” button, the CaclTest.java will be created for you.

Benefits from JUnit

I'm in too much of a hurry!

 

In article <Test Infected>, there is a very classic comment on our traditional coding pattern that we code without unit tests.

 

Every programmer knows they should write tests for their code. Few do. The universal response to "Why not?" is "I'm in too much of a hurry." This quickly becomes a vicious cycle- the more pressure you feel, the fewer tests you write. The fewer tests you write, the less productive you are and the less stable your code becomes. The less productive and accurate you are, the more pressure you feel.

 

I really appreciate the concise comments on the situation a coder often encounters. Yes, I really felt the pressure when I write SNMP Agent code on embedded OS two years before. As you know, there is no Unit Test Framework available on an embedded OS. So I have to review the code again and again, have to think about the logic again and again, for I have no other ways to verify my code. We feared to change anything in that time.

 

I think a Unit Test Framework like JUnit can release us from the pressure. Meaning well, we can get more benefits than this from a Unit Test Framework.

 

Code with confidence

 

Software is soft! No matter how small a software project is, it will not stop to change and evolve. In the traditional coding pattern, the most painful thing to a coder is the fear to change code for there is no easy and automatically method to verify the change. Most time we have to launch the whole system to verify a trivial change to a few lines of code.

 

Coding with JUnit will release us from the fear to change. Every time we fix a bug or refactor some code, we run all the test cases again. If all the test cases pass, we can ensure the change do not break anything.

 

The more test cases we write, the more confident we are in our code.

 

More productive

 

From my experience, we often take a small part of time to write runtime code and the left part of time to do debug or IT manually. Writing test cases will shorten the time of debug or IT dramatically.

 

Produce apparent and clean code

 

As we all know, unit test belongs to white-box test method. It aims to test the code logic and inner-structure. A good unit test will make code inner-structure apparent, will improve code quality dramatically.

 

In traditional coding pattern, we treat unit test as a separate phase which is following to coding phase. But we never attach importance to this phase. We often bypass it and does integration test immediately after coding. Why do we bypass it? The core reason is that it is very difficult to do unit test in a separate phase. By coding with JUnit, unit test is not a separate phrase any more, but is a part of coding phase. So we can build a unit test system for our code when we are coding.

 

Produce good document for your code

 

What’s the purpose of writing documents in software development? Communication! We explain our intention and design to other developers with documents. We can write word, txt or other format files to explain our code, why not just write code to explain code?

 

So I think a test case for an API is the best doc to introduce how to use it. When I read Open Source code, I often try to find its test code to learn how to use an API. I think it is a better way for me to understand the design intent of the author.

 

Best Practices

 

Think about test first

 

No loose coupling software design is born in this world. Always think about how to test your code before you write them down.  This is the only way to produce loose coupling software design.

 

There are too many examples in Open Source community.  We always appreciate the talent design from mentors such as Erich Gamma , Kent Beck and so on. But do you pay attention to the coding pattern they adopt?  They all adopt TDD (Test-Driven Development) method. They write test case first, then write runtime code.

Test what you want to test and you can test first

 

Don’t try to make your test cases to cover all of you code. Unit test theory maybe suggests you to cover all logic paths, all boundaries. But it is just a theory!

 

I don’t mean the theory is not correct. I just think it will make one tiered of writing too many test cases, finally one may be bored and write nothing any more.

 

Write a few test cases for your code first; writing more later if you think they take effect.

 

Don’t try to test GUI view, but try to test GUI model.

 

Test GUI is always difficult. I don’t find efficient methods or tools to do this work.

 

So try to separate your GUI view from your GUI model, then test your model.

 

Examples

 

1.       TFTP Tool for NM4000.

 

VoB: BBNetMan_SRCNew/TestSrc

 

2.       Site Manager Tool for iPlatform

 

Source code has not been merged to ClearCase.

 

References

 

Please access www.junit.org website to find all of them.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值