JUnit入门文章(转)(包括英文原文及中文译文)

英文原文转自:http://www.clarkware.com/articles/JUnitPrimer.html

中文译文转自:http://140.109.17.94/ArecaChen/Test/JUnit_Primer.htm

××××××××××××××××××××××××××××××××××××××××××××××××××××××××

英文原文:

JUnit Primer

Summary

This article demonstrates a quick and easy way to write and run JUnit test cases and test suites. We'll start by reviewing the key benefits of using JUnit and then write some example tests to demonstrate its simplicity and effectiveness.

The two-day, on-site Test-Driven Development with JUnit Workshop is an excellent way to learn JUnit and test-driven development through lecture and a series of hands-on exercises guided by Mike Clark.

Table of Contents

This article contains the following sections:

Introduction

Why Use JUnit?

Design of JUnit

Step 1: Install JUnit

Step 2: Write a Test Case

Step 3: Write a Test Suite

Step 4: Run the Tests

Step 5: Organize the Tests

Testing Idioms

Training and Mentoring

Resources

Why Use JUnit?

Before we begin, it's worth asking why we should use JUnit at all. The subject of unit testing always conjures up visions of long nights slaving over a hot keyboard trying to meet the project's test case quota. However, unlike the Draconian style of conventional unit testing, using JUnit actually helps you write code faster while increasing code quality. Once you start using JUnit you'll begin to notice a powerful synergy emerging between coding and testing, ultimately leading to a development style of only writing new code when a test is failing.

Here are just a few reasons to use JUnit:

JUnit tests allow you to write code faster while increasing quality.

Yeah, I know, it sounds counter-intuitive, but it's true! When you write tests using JUnit, you'll spend less time debugging, and you'll have confidence that changes to your code actually work. This confidence allows you to get more aggressive about refactoring code and adding new features.

Without tests, it's easy to become paranoid about refactoring or adding new features because you don't know what might break as a result. With a comprehensive test suite, you can quickly run the tests after changing the code and gain confidence that your changes didn't break anything. If a bug is detected while running tests, the source code is fresh in your mind, so the bug is easily found. Tests written in JUnit help you write code at an extreme pace and spot defects quickly.

JUnit is elegantly simple.

Writing tests should be simple - that's the point! If writing tests is too complex or takes too much time, there's no incentive to start writing tests in the first place. With JUnit, you can quickly write tests that exercise your code and incrementally add tests as the software grows.

Once you've written some tests, you want to run them quickly and frequently without disrupting the creative design and development process. With JUnit, running tests is as easy and fast as running a compiler on your code. In fact, you should run your tests every time you run the compiler. The compiler tests the syntax of the code and the tests validate the integrity of the code.

JUnit tests check their own results and provide immediate feedback.

Testing is no fun if you have to manually compare the expected and actual result of tests, and it slows you down. JUnit tests can be run automatically and they check their own results. When you run tests, you get simple and immediate visual feedback as to whether the tests passed or failed. There's no need to manually comb through a report of test results.

JUnit tests can be composed into a hierarchy of test suites.

JUnit tests can be organized into test suites containing test cases and even other test suites. The composite behavior of JUnit tests allows you to assemble collections of tests and automatically regression test the entire test suite in one fell swoop. You can also run the tests for any layer within the test suite hierarchy.

Writing JUnit tests is inexpensive.

Using the JUnit testing framework, you can write tests cheaply and enjoy the convenience offered by the testing framework. Writing a test is as simple as writing a method that exercises the code to be tested and defining the expected result. The framework provides the context for running the test automatically and as part of a collection of other tests. This small investment in testing will continue to pay you back in time and quality.

JUnit tests increase the stability of software.

The fewer tests you write, the less stable your code becomes. Tests validate the stability of the software and instill confidence that changes haven't caused a ripple-effect through the software. The tests form the glue of the structural integrity of the software.

JUnit tests are developer tests.

JUnit tests are highly localized tests written to improve a developer's productivity and code quality. Unlike functional tests, which treat the system as a black box and ensure that the software works as a whole, unit tests are written to test the fundamental building blocks of the system from the inside out.

Developer's write and own the JUnit tests. When a development iteration is complete, the tests are promoted as part and parcel of the delivered product as a way of communicating, "Here's my deliverable and the tests which validate it."

JUnit tests are written in Java.

Testing Java software using Java tests forms a seamless bond between the test and the code under test. The tests become an extension to the overall software and code can be refactored from the tests into the software under test. The Java compiler helps the testing process by performing static syntax checking of the unit tests and ensuring that the software interface contracts are being obeyed.

JUnit is free!

Design of JUnit

JUnit is designed around two key design patterns: the Command pattern and the Composite pattern.

A TestCase is a command object. Any class that contains test methods should subclass the TestCase class. A TestCase can define any number of public testXXX() methods. When you want to check the expected and actual test results, you invoke a variation of the assert() method.

TestCase subclasses that contain multiple testXXX() methods can use the setUp() and tearDown() methods to initialize and release any common objects under test, referred to as the test fixture. Each test runs in the context of its own fixture, calling setUp() before and tearDown() after each test method to ensure there can be no side effects among test runs.

TestCase instances can be composed into TestSuite hierarchies that automatically invoke all the testXXX() methods defined in each TestCase instance. A TestSuite is a composite of other tests, either TestCase instances or other TestSuite instances. The composite behavior exhibited by the TestSuite allows you to assemble test suites of test suites of tests, to an arbitrary depth, and run all the tests automatically and uniformly to yield a single pass or fail status.

Step 1: Install JUnit

First, download the latest version of JUnit, referred to below as junit.zip.

Then install JUnit on your platform of choice:

Windows

To install JUnit on Windows, follow these steps:

Unzip the junit.zip distribution file to a directory referred to as %JUNIT_HOME%.

Add JUnit to the classpath:

set CLASSPATH=%JUNIT_HOME%\junit.jar

Unix (bash)

To install JUnit on Unix, follow these steps:

Unzip the junit.zip distribution file to a directory referred to as $JUNIT_HOME.

Add JUnit to the classpath:

export CLASSPATH=$JUNIT_HOME/junit.jar

Test the installation by using either the textual or graphical test runner to run the sample tests distributed with JUnit.

Note: The sample tests are not contained in the junit.jar, but in the installation directory directly. Therefore, make sure that the JUnit installation directory is in the CLASSPATH.

To use the textual test runner, type:

java junit.textui.TestRunner junit.samples.AllTests

To use the graphical test runner, type:

java junit.swingui.TestRunner junit.samples.AllTests

All the tests should pass with an "OK" (textual runner) or a green bar (graphical runner). If the tests don't pass, verify that junit.jar is in the CLASSPATH.

Step 2: Write a Test Case

First, we'll write a test case to exercise a single software component. We'll focus on writing tests that exercise the component behavior that has the highest potential for breakage, thereby maximizing our return on testing investment.

To write a test case, follow these steps:

Define a subclass of TestCase.

Override the setUp() method to initialize object(s) under test.

Optionally override the tearDown() method to release object(s) under test.

Define one or more public testXXX() methods that exercise the object(s) under test and assert expected results.

The following is an example test case:

Example JUnit Test Case

import junit.framework.TestCase;

public class ShoppingCartTest extends TestCase {

    private ShoppingCart cart;

    private Product book1;

    /**

     * Sets up the test fixture.

     *

     * Called before every test case method.

     */

    protected void setUp() {

        cart = new ShoppingCart();

        book1 = new Product("Pragmatic Unit Testing", 29.95);

        cart.addItem(book1);

    }

    /**

     * Tears down the test fixture.

     *

     * Called after every test case method.

     */

    protected void tearDown() {

        // release objects under test here, if necessary

    }

    /**

     * Tests emptying the cart.

     */

    public void testEmpty() {

        cart.empty();

   

        assertEquals(0, cart.getItemCount());

    }

    /**

     * Tests adding an item to the cart.

     */

    public void testAddItem() {

        Product book2 = new Product("Pragmatic Project Automation", 29.95);

        cart.addItem(book2);

        double expectedBalance = book1.getPrice() + book2.getPrice();

 

        assertEquals(expectedBalance, cart.getBalance(), 0.0);

        assertEquals(2, cart.getItemCount());

    }

    /**

     * Tests removing an item from the cart.

     *

     * @throws ProductNotFoundException If the product was not in the cart.

     */

    public void testRemoveItem() throws ProductNotFoundException {

        cart.removeItem(book1);

        assertEquals(0, cart.getItemCount());

    }

    /**

     * Tests removing an unknown item from the cart.

     *

     * This test is successful if the

     * ProductNotFoundException is raised.

     */

    public void testRemoveItemNotInCart() {

        try {

            Product book3 = new Product("Pragmatic Version Control", 29.95);

            cart.removeItem(book3);

            fail("Should raise a ProductNotFoundException");

        } catch(ProductNotFoundException expected) {

            // successful test

        }

    }

}

(The complete source code for this example is available in the Resources section).

Step 3: Write a Test Suite

Next, we'll write a test suite that includes several test cases. The test suite will allow us to run all of its test cases in one fell swoop.

To write a test suite, follow these steps:

Write a Java class that defines a static suite() factory method that creates a TestSuite containing all the tests.

Optionally define a main() method that runs the TestSuite in batch mode.

The following is an example test suite:

Example JUnit Test Suite

import junit.framework.Test;

import junit.framework.TestSuite;

public class EcommerceTestSuite {

    public static Test suite() {

        TestSuite suite = new TestSuite();

        //

        // The ShoppingCartTest we created above.

        //

        suite.addTestSuite(ShoppingCartTest.class);

        //

        // Another example test suite of tests.

        //

        suite.addTest(CreditCardTestSuite.suite());

        //

        // Add more tests here

        //

        return suite;

    }

    /**

     * Runs the test suite using the textual runner.

     */

    public static void main(String[] args) {

        junit.textui.TestRunner.run(suite());

    }

}

Step 4: Run the Tests

Now that we've written a test suite containing a collection of test cases and other test suites, we can run either the test suite or any of its test cases individually. Running a TestSuite will automatically run all of its subordinate TestCase instances and TestSuite instances. Running a TestCase will automatically invoke all of its public testXXX() methods.

JUnit provides both a textual and a graphical user interface. Both user interfaces indicate how many tests were run, any errors or failures, and a simple completion status. The simplicity of the user interfaces is the key to running tests quickly. You should be able to run your tests and know the test status with a glance, much like you do with a compiler.

To run our test case using the textual user interface, use:

java junit.textui.TestRunner ShoppingCartTest

The textual user interface displays "OK" if all the tests passed and failure messages if any of the tests failed.

To run the test case using the graphical user interface, use:

java junit.swingui.TestRunner ShoppingCartTest

The graphical user interface displays a Swing window with a green progress bar if all the tests passed or a red progress bar if any of the tests failed.

The EcommerceTestSuite can be run similarly:

java junit.swingui.TestRunner EcommerceTestSuite

Step 5: Organize the Tests

The last step is to decide where the tests will live within our development environment.

Here's the recommended way to organize tests:

Create test cases in the same package as the code under test. For example, the com.mydotcom.ecommerce package would contain all the application-level classes as well as the test cases for those components.

To avoid combining application and testing code in your source directories, create a mirrored directory structure aligned with the package structure that contains the test code.

For each Java package in your application, define a TestSuite class that contains all the tests for validating the code in the package.

Define similar TestSuite classes that create higher-level and lower-level test suites in the other packages (and sub-packages) of the application.

Make sure your build process includes the compilation of all tests. This helps to ensure that your tests are always up-to-date with the latest code and keeps the tests fresh.

By creating a TestSuite in each Java package, at various levels of packaging, you can run a TestSuite at any level of abstraction. For example, you can define a com.mydotcom.AllTests that runs all the tests in the system and a com.mydotcom.ecommerce.EcommerceTestSuite that runs only those tests validating the e-commerce components.

The testing hierarchy can extend to an arbitrary depth. Depending on the level of abstraction you're developing at in the system, you can run an appropriate test. Just pick a layer in the system and test it!

Here's an example test hierarchy:

Example JUnit Test Hierarchy

AllTests (Top-level Test Suite)

    SmokeTestSuite (Structural Integrity Tests)

        EcommerceTestSuite

            ShoppingCartTestCase

            CreditCardTestSuite

                AuthorizationTestCase

                CaptureTestCase

                VoidTestCase

            UtilityTestSuite

                MoneyTestCase

        DatabaseTestSuite

            ConnectionTestCase

            TransactionTestCase

    LoadTestSuite (Performance and Scalability Tests)

        DatabaseTestSuite

            ConnectionPoolTestCase

        ThreadPoolTestCase

Testing Idioms

Keep the following things in mind when writing JUnit tests:

The software does well those things that the tests check.

Test a little, code a little, test a little, code a little...

Make sure all tests always run at 100%.

Run all the tests in the system at least once per day (or night).

Write tests for the areas of code with the highest probability of breakage.

Write tests that have the highest possible return on your testing investment.

If you find yourself debugging using System.out.println(), write a test to automatically check the result instead.

When a bug is reported, write a test to expose the bug.

The next time someone asks you for help debugging, help them write a test.

Write unit tests before writing the code and only write new code when a test is failing.

Training and Mentoring

Reduce defects and improve design and code quality with a two-day, on-site Test-Driven Development with JUnit Workshop that quickly spreads the testing bug throughout your team.

I also offer JUnit mentoring to help your keep the testing momentum.

Contact me for more information.

Resources

Source Code - Complete source code for the ShoppingCartTest example

JUnit - The official JUnit website

JUnit FAQ - Frequently asked questions and answers

A Dozen Ways to Get the Testing Bug by Mike Clark (java.net, 2004)

Pragmatic Unit Testing by Andy Hunt and Dave Thomas (The Pragmatic Programmers, 2003)

JUnitPerf - JUnit test decorators for continuous performance testing

JDepend - A Java package dependency analyzer with example JUnit test cases

About the Author

Mike Clark is a consultant, author, speaker, and most important, he's an experienced programmer. He is the developer of JUnitPerf, an open source collection of JUnit extensions for continuous performance testing. He also wrote the JUnit FAQ and serves as its editor for the JUnit community. Mike frequently writes and speaks on test-driven development using JUnit. He helps teams build better software faster through his company, Clarkware Consulting, Inc.

Copyright © 1999-2005 Clarkware Consulting, Inc.

All Rights Reserved

×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××

中文译文:

JUnit入門

 

 摘要

本文展示如何使用JUnit測試框架撰寫及執行簡單的測試案例及測試系列。 

 

原作者:Mike Clark Clarkware Consulting, Inc. October 7, 2000

翻譯:Areca Chen 2002/1/23

 

 

  簡介

本文的目的是展示一個撰寫及執行JUnit測試案例及測試系列(suites)(或測試包)簡單快速的方法。我們一開始先探討使用JUnit的主要優點然後撰寫一些測試範例以展示其簡單性及效力。

本文包含下列各節:

簡介

為什麼使用JUnit?

JUnit的設計

第一步:撰寫一個測試案例

第二步:撰寫一個測試系列

第三步:執行測試

第四步:組織測試

測試慣例

訓練及顧問指導

資源

 

在你開始之前,請確認你已下載並安裝下列的軟體:

JUnit (3.1 or later)

 

 為什麼使用JUnit?

在我們開始之前,我們要問為什麼我們要使用JUnit?單元測試的主題呈現在我們腦中的往往是長夜的思考試著去符合專案測試案例的配額。不管如何,不像傳統單元測試的殘酷特性,使用JUnit實際上在你提升程式碼的品質時JUnit測試仍允許你更快速的撰寫程式。只要你開始使用JUnit你將開始注意到介於程式碼及測試之間有一個強大的結合力,最終你的開發風格是只有當一個失敗的測試時才寫新的程式碼(only writing new code when a test is failing)。

以下列出使用JUnit的理由:

 

在你提升程式碼的品質時JUnit測試仍允許你更快速的撰寫程式

是的,我知道,那聽起來似乎不是很直覺,但那是事實。當你使用JUnit撰寫測試,你將花更少的時間除蟲,同時對你程式碼的改變更 俱有信心。這個信心讓你更積極重整程式碼並增加新的功能。沒有測試,對於重整及增加新功能你會變得沒有信心;因為你不知道有甚麼東西會破壞產出的結果。採用一個綜合的測試系列,你可以在改變程式碼之後快速的執行多個測試並對於你的變動並未破壞任何東西感到有信心。在執行測試時如果發現臭蟲,原始碼仍然清楚的在你腦中,因此很容易找到臭蟲。在JUnit中撰寫的測試幫助你以一種極 大(extreme)的步伐撰寫程式及快速的找出缺點。

JUnit非常簡單

撰寫測試應該很簡單--這是重點!如果撰寫測試太複雜或太耗時間,便無法要求程式設計師撰寫測試。使用JUnit你可以快速的撰寫測試並檢測你的程式碼並逐 步隨著程式碼的成長增加測試。只要你寫了一些測試,你想要快速並頻繁的執行測試而不至於中斷建立設計及開發程序。使用JUnit執行測試就像編譯你的程式碼那麼容易。事實上,你應該執行編譯時也執行測試。編譯是 檢測程式碼的語法而測試是檢查程式碼的完整性(integrity)。

JUnit測試檢驗其結果並提供立即的回饋。

如果你是以人工比對測試的期望與實際結果那麼測試是很不好玩的,而且讓你的速度慢下來。JUnit測試可以自動執行並且檢查他們自己的結果。當你執行測試,你獲得簡單且立即的回饋; 比如測試是通過或失敗。而不再需要人工檢查測試結果的報告。

JUnit測試可以合成一個測試系列的層級架構。

JUnit可以把測試組織成測試系列;這個測試系列可以包含其他的測試或測試系列。JUnit測試的合成行為允許你組合多個測試並自動的回歸(regression)從頭到尾測試整個測試系列。你也可以執行測試系列層級架構中任何一層的測試。

撰寫JUnit測試所費不多。

使用Junit測試框架,你可以很便宜的撰寫測試並享受由測試框架所提供的信心。撰寫一個測試就像寫一個方法一樣簡單;測試是檢驗要測試的程式碼並定義期望的結果。這個測試框架提供自動執行測 試的背景;這個背景並成為其他測試集合的一部份。在測試少量的投資將持續讓你從時間及品質中獲得回收。

JUnit測試提升軟體的穩定性。

你寫的測試愈少;你的程式碼變的愈不穩定。測試使得軟體穩定並逐步累積信心;因為任何變動不會造成漣漪效應而漫及整個軟體。測試可以形成軟體的完整結構的膠結。

JUnit測試是開發者測試。

JUnit測試是高度區域性(localized)測試;用以改善開發者的生產力及程式碼品質。不像功能測試(function test)視系統為一個黑箱以確認軟體整體的工作性為主,單元測試是由內而外測試系統基礎的建構區塊。開發者撰寫並擁有JUnit測試。每當一個開發反覆(iteration)完成,這個測試便包裹成為交付軟體的一部份 提供一種溝通的方式,「這是我交付的軟體並且是通過測試的。」

JUnit測試是以Java寫成的。

使用Java測試Java軟體形成一個介於測試及程式碼間的無縫(seamless)邊界。在測試的控制下測試變成整個軟體的擴充同時程式碼可以被重整。Java編譯器的單元測試靜態語法檢查可已幫助測試程序並且確認遵守軟體介面的約定。

JUnit是免費的(JUnit is free.)

 

 JUnit的設計

JUnit是以兩個關鍵設計樣式來設計的:指令樣式(Command pattern)及合成樣式(Composite pattern)。

TestCase是一個指令物件。任何包含測試方法的類別都是TestCase的子類別。TestCase可以定義任意數量的testXXX()方法。當你要檢查期望與實際的測試結果,你啟動assert()方法的各種類型(variaton)。

TestCase子類別包含多個testXXX()方法;可以使用setUp()及tesrDown()方法初始化及釋放測試下的任何一般的物件,這個子類別形同測試的基礎設備(fixture)。每一個測試在其本身基礎設備的背景下執行,在每一個測試方法之前呼叫setUp()及之後呼叫tearDown()以確保沒有副作用影響測試的執行。

TestCase實例物件可以合成為TestSuite層級架構;在這個TestSuite層級架構中可以自動啟動定義在TestCase實例物件中的所有testXXX()方法。一個TestSuite是其他多個測試的一個合成物件(composite),其中包括TestCase實例物件及其他的TestSuite實例物件。這個由TestSuite代表的合成物件行為允許你組合測試的測試系列的測試系列到任意深度,並且自動一致性(uniformly)的執行所有測試以產出個別的通過或失敗的狀態。

 

第一步:撰寫一個測試案例

首先,我們將撰寫一個測試案例以便檢測單一軟體元件。我們將聚焦於撰寫測試;這個測試檢驗這個元件的行為;而這個物件的行為是有著最高的破損的可能性,因此可以從測試的投資獲得最大的回收。

撰寫測試案例請依據下列的步驟:

定義一個TestCase的子類別。

覆寫setUp()方法以初始化測試中的一個或多個物件。

覆寫tearDown()方法以釋放測試中的一個或多個物件。

定義一個或多個公開的testXXX()方法;這些方法檢驗這些測試中的物件並且評估期望的結果。

定義一個靜態的suite()工廠方法;這個工廠方法構建一個TestSuite其中包含TestCase的所有testXXX()方法。

隨意的定義一個main()方法以批次的方式執行TestCase。

 

下列是一個測試案例的範例:

(這個範例完整的程式碼可以在資源一節中找的到。)

測試案例的範例(Example Test Case)

import junit.framework.Test;

import junit.framework.TestCase;

import junit.framework.TestSuite;

public class ShoppingCartTest extends TestCase {

    private ShoppingCart _bookCart;

    private Product _defaultBook;

    /**

     *以特定名稱建構一個ShoppingCartTest。

     *

     *建構函數是以測試案例的名稱當作參數

     */

    public ShoppingCartTest(String name) {

        super(name);

    }

    /**

     * 設定測試設備

     *在測試案例方法之前呼叫

     * /

    protected void setUp() {

        _bookCart = new ShoppingCart();

        _defaultBook = new Product("Extreme Programming", 23.95);

        _bookCart.addItem(_defaultBook);

    }

    /**

     *釋放測試設備

     *

     *在測試案例方法之後呼叫

     *

     */

    protected void tearDown() {

        _bookCart = null;

    }

    /**

     *測試在cart中增加一個產品

     *

     */

    public void testProductAdd() {

        Product newBook = new Product("Refactoring", 53.95);

        _bookCart.addItem(newBook);

        double expectedBalance = _defaultBook.getPrice() + newBook.getPrice();

 

        assertEquals(expectedBalance, _bookCart.getBalance(), 0.0);

        assertEquals(2, _bookCart.getItemCount());

    }

    /**

     *測試清空cart

     *

     */

    public void testEmpty() {

        _bookCart.empty();

   

        assertTrue(_bookCart.isEmpty());

    }

    /**

     *測試從cart中移除產品

     *

     *如果此產品不在cart中丟出一個ProductNotFoundException的例外

     *

     */

    public void testProductRemove() throws ProductNotFoundException {

        _bookCart.removeItem(_defaultBook);

        assertEquals(0, _bookCart.getItemCount());

        assertEquals(0.0, _bookCart.getBalance(), 0.0);

    }

    /**

     *測試從cart中移除一個未知的產品

     *

     *如果ProductNotFoundException例外產生表示測試成功

     *

     */

    public void testProductNotFound() {

        try {

            Product book = new Product("Ender's Game", 4.95);

            _bookCart.removeItem(book);

            fail("Should raise a ProductNotFoundException");

        } catch(ProductNotFoundException success) {

            // 測試成功

        }

    }

    /**

     *組合並傳回一個這個測試案例所有測試方法的測試系列

     *傳回一個非空值(non-null)的測試系列

     */

    public static Test suite() {

        //這裡使用的想法是加入所有的testXXX()方法到測試系列中。

        //

        TestSuite suite = new TestSuite(ShoppingCartTest.class);

        //下面是另一種作法,但增加愈多的測試案例方法愈有可能發生錯誤

        //

        // TestSuite suite = new TestSuite();

        // suite.addTest(new ShoppingCartTest("testEmpty"));

        // suite.addTest(new ShoppingCartTest("testProductAdd"));

        // suite.addTest(new ShoppingCartTest("testProductRemove"));

        // suite.addTest(new ShoppingCartTest("testProductNotFound"));

        //

        return suite;

    }

    /**

     *執行此測試案例(Runs the test case)

     */

    public static void main(String args[]) {

        junit.textui.TestRunner.run(suite());

    }

}

 

 

 

  第二步:撰寫一個測試系列

其次,我們將撰寫一個測試系列其中包含許多測試案例。此測試系列將允許我們從頭到尾執行其所有的測試案例。

撰寫測試系列請依循下列的步驟:

定義一個TestCase的子類別。

定義一個靜態的suite()工廠方法;這個方法構建一個TestSuite以包含所以的測試。

隨意定義一個main()方法以批次方式執行這個TestSuite。

下列是測試系列的範例:

測試系列範例(Example Test Suite)

import junit.framework.Test;

import junit.framework.TestCase;

import junit.framework.TestSuite;

public class EcommerceTestSuite extends TestCase {

    /**

     * 以特定名稱建構一個EcommerceTestSuite

     *

     *建構函數是以測試案例的名稱當作參數

     */

    public EcommerceTestSuite(String name) {

        super(name);

    }

    /**

     *組合並傳回一個測試系列包含所有已知的測試。

     *新的測試應該在此加入

     *傳回一個非空值(non-null)的測試系列

     */

    public static Test suite() {

        TestSuite suite = new TestSuite();

        //我們在前面構建的ShoppingCartTest

        //

        suite.addTest(ShoppingCartTest.suite());

        //另一個測試系列的範例,在測試系列中加入其他的測試系列

        //

        suite.addTest(CreditCardTestSuite.suite());

        return suite;

    }

    /**

     *執行此測試系列

     */

    public static void main(String args[]) {

        junit.textui.TestRunner.run(suite());

    }

}

 

 

 

第三步:執行測試

現在我們撰寫了一個測試系列其中包含一堆測試案例及其他的測試系列,我們可以執行這個測試系列或者其中任何個別的測試案例。執行TestSuite將自動執行所有的TestCase及TestSuite實例物件。執行一個TestCase將自動啟動其所有公開的testXXX()方法。

JUnit提供文字及圖形使用者界面。兩種使用者介面都可以指出多少個測試被執行、任何錯誤或失敗、及一個簡單的完成狀態。簡化使用者介面是快速執行測試的關鍵。你應該簡單瞭解就能夠執行你的測試並知道測試的狀態,就像你在編譯上所做的一樣。

文字使用者介面(junit.textui.TestRunner)如果通過所有測試則顯示『OK』而如果失敗則顯示失敗訊息。

圖形使用者界面(junit.swingui.TestRunner)顯示浮動視窗;如果所有測試皆通過則其中有一個進度桿顯示為綠色,否則進度桿顯示為紅色。

一般而言,TestSuite及TestCase類別應定義一個main()方法;main()利用適當的使用者介面。我們寫的測試到目前為止皆定義一個main()方法來使用文字使用者介面。

由main()定義的使用文字使用者介面執行我們的測試案例時,使用:

java ShoppingCartTest

另一種方式,使用文字使用者介面執行測試,使用:

java junit.textui.TestRunner ShoppingCartTest

或這使用圖形使用者介面時,使用:

java junit.swingui.TestRunner ShoppingCartTest

EcommerceTestSuite可以以類似的方法執行。

 

第四步:組織測試

最後一步是決定測試在我們的開發環境中應存在於何處。

這裡有一些建議如何組織我們的測試:

把測試案例建立在與我們要測試的程式碼相同的包裹(package)中。例如:com.mydotcom.ecommerce包裹包含所有的應用程式階 級的類別及這些元件的測試案例。

在你的原始碼資料夾中避免結合應用程式與測試程式碼,建立一個鏡射(mirrored)的資料夾結構對應於此包裹結構;並在鏡射資料夾中存放你的測試碼。

為你的應用程式中的Java包裹定義一個TestSuite類別;在這個TestSuite類別中包含所有測試這個包裹內之程式的測試。

定義類似的TestSuite類別;此TestSuite類別在此應用程式中的其他包裹(及子包裹)中構建高階及低階測試系列。

確認你的建構程序包含所有測試的編輯物(compilation)。這樣做有助於確認你的測試可以保持與最後的程式碼同步以維持測試是最新的。

經由在每一個Java包裹中建立一個TestSuite,在各種包裹層次中,你可以在每一個抽象層中執行一個TestSuite。例如,你可以定義一個com.mydotcom.AllTests執行系統中所有的測試,及定義一個com.mydotcom.ecommerce.EcommerceTestSuite只有執行電子交易元件的測試。

測試層級架構可以擴充到任意的深度。其深度與你開發系統的抽象層次有關,你可以執行一個相稱的測試。只要選擇你的系統層次並測試它即可。

下面的範例是測是的層級架構:

測試層級架構範例(Example Testing Hierarchy)

AllTests (Top-level Test Suite)

    SmokeTestSuite (Structural Integrity Tests)

        EcommerceTestSuite

            ShoppingCartTestCase

            CreditCardTestSuite

                AuthorizationTestCase

                CaptureTestCase

                VoidTestCase

            UtilityTestSuite

                MoneyTestCase

        DatabaseTestSuite

            ConnectionTestCase

            TransactionTestCase

    LoadTestSuite (Performance and Scalability Tests)

        DatabaseTestSuite

            ConnectionPoolTestCase

        ThreadPoolTestCase

 

 

 

測試慣例

當你測試時請謹記下面的事項:

軟體運作良好的事物都是經過測試檢驗的。

測試一點點,程式碼寫一點點,測試一點點,程式碼寫一點點......

請確認所有測試都能100%通過。

每天(夜)至少執行系統中所有的測試一次。

要測試的程式碼是最可能錯誤的區域。

撰寫最可能回收測試投資的測試。

如果你使用System.out.println()除蟲,寫一個測試自動檢查其結果。

如果發現臭蟲,寫一個測試揭露這個臭蟲。

如果下次有人要求你幫他除蟲,幫他寫一個測試。

撰寫程式碼之前先寫單元測試;而且只有當一個測試失敗才寫新的程式碼。

 

訓練及顧問指導

想要學習更多有關測試嗎?身為Clarkware Consulting的首席顧問,我提供線上JUnit訓練及顧問指導服務幫助你的團隊使用JUnit提升生產力及有效的應用JUnit測試你的專案。開發服務有可以幫你的專案成功。這些服務可以量身訂製以符合你特殊專案的需求。

請以email 或電話720.851.2014與我聯絡。

 

資源

Source Code -ShoppingCartTest範例完整的原始碼。

JUnit - 官方網站

JUnit Cookbook -手冊

JUnit FAQ

"JUnit Test Infected: Programmers Love Writing Tests" by Gamma, E. and Beck, K.

"JUnit A Cook's Tour" by Gamma, E. and Beck, K.

JUnitPerf -收集JUnit測試修飾者(decorators)用以衡量包含於現有JUnit測試的功能其執行效率及可達成性(scalability) (A collection of JUnit test decorators used to measure the performance and scalability of functionality contained within existing JUnit tests.)

JDepend -  一個Java包裹相關的分析器包含JUnit測試案例的範例。(A Java package dependency analyzer with example JUnit test cases)

Java Tools for Extreme Programming: Mastering Open Source Tools Including Ant, JUnit, and Cactus, by Richard Hightower, Nicholas Lesiecki (John Wiley & Sons, 2001)

Refactoring: Improving The Design Of Existing Code, by Fowler, M. (Addison-Wesley, 1999)

Extreme Programming Explained, by Beck, K. (Addison-Wesley, 2000)

--------------------------------------------------------------------------------

作者簡介(About the author)

Mike Clark是Clarkware Consulting, Inc.的首席顧問,提供客戶的軟體架構、設計、開發、及執行效率諮詢。Mike有十年左右使用各種技術開發及交付軟體的經驗及五年實際經驗的Java專家;在Java中的經驗強調使用J2EE技術於伺服器端的開發。 

 

--------------------------------------------------------------------------------

Copyright © 1999-2001 Clarkware Consulting, Inc.

All Rights Reserved

本文獲授權同意翻譯函:

Hi Areca,

You may translate the JUnit Primer as long as the original copyright

remains intact and the text is translated without further modification.

Enjoy!

Mike

=====

Mike Clark

Clarkware Consulting, Inc.

http://www.clarkware.com

720.851.2014

Dear  Mike,

I've read the articles " Junit Primer"on the web site and like it very much.

It will be great if I could translate it into traditional Chinese and publish on our own site http://www.dotspace.idv.tw) to help those who want to explore JUnit more. I will, of course, declare the source and "hyperlink" those to your original documents. I'll be very grateful if you could give your authorization for me to do this.

Our web site contents about software engineering topics like XP, UML, Rup, Design Patterns, Framework, those are all in traditional Chinese.

        Regards,

Areca Chen

2002/2/8