単体テスト

JUnit

<dependency>

<groupId>junit</groupId>

<artifactId>junit</artifactId>

<version>4.11</version>

<scope>test</scope>

</dependency>

テスト対象

public class Target{

public int divid(int a, int b){

return a / b;

}

}

テストコード(JUnit 4)

import static org.junit.Assert.*;

import org.junit.Before;

import org.junit.BeforeClass;

import org.junit.AfterClass;

import org.junit.After;

import org.junit.Ignore;

import org.junit.Test;

public class TargetTest{

private Target target = new Target();

// すべてのメソッドの前処理

@BeforeClass

public static void init(){ // staticメソッドが必要

// do something

}

// すべてのメソッドの後処理

@AfterClass

public static void dispose(){ // staticメソッドが必要

// do something

}

// 毎メソッドの前処理

@Before

public void before(){

// do something

}

// 毎メソッドの後処理

@After

public void after(){

// do something

}

// 正常系テストケース

@Test

public void testNormal(){

assertEquals(10, target.divid(100, 10));

}

// 境界線テストケース

@Test

public void testBorder(){

assertEquals(0, target.divid(Integer.MAX_VALUE, Integer.MIN_VALUE));

assertEquals(-1, target.divid(Integer.MIN_VALUE, Integer.MAX_VALUE));

}

// 異常系テストケース

@Test(expected=ArithmeticException.class)

public void testException(){

target.divid(100, 0);

}

@Ignore // 実行しない

@Test(timeout=100) // 100ms内に実行完了

public void testOther(){

// do something

}

}

★Testing privateメソッド(By Reflection)

@Test

public void test() throws Exception {

Method method

= Sample.class.getDeclaredMethod(

"targetMethod", String.class, String.class);

method.setAccessible(true);


Sample sample = new Sample();

String result = (String) method.invoke(sample, "xxx", "yyy");


assertEquals("expected", result);

}

★Springテスト

import org.junit.runner.RunWith;

import org.junit.Test;

import org.springframework.test.context.ContextConfiguration;

import org.springframework.test.annotation.Timed;

import org.springframework.beans.factory.annotation.Autowired;

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations = {"/spring-test.xml"})

public class MyServiceTest {

@Autowired

private MyService myService;

@Test

@Timed(millis=1000)

public void testXxx() {

...

}

}

★EJB(JavaEE 6)テスト

import javax.ejb.embeddable.EJBContainer;

import javax.naming.Context;

import javax.naming.NamingException;

public class BookEJBTest {

private static EJBContainer ec;

private static Context ctx;

@BeforeClass

public static void initContainer() throws Exception {

ec = EJBContainer.createEJBContainer();

ctx = ec.getContext();

}

@AfterClass

public static void closeContainer() throws Exception {

if (ec != null) {

ec.close();

}

}

@Test

public void testCreateBook() throws NamingException {

Book book = new Book();

book.setTitle("xxx");

...

BookEJB bookEJB =

(BookEJB) ctx.lookup("java:global/classes/BookEJB");

book = bookEJB.createBook(book);

assertNotNull(book.getId());

List<Book> books = bookEJB.findBooks();

assertNotNull(books);

}

}

private Context ctx;

@Before

public void setUp() throws Exception {

ctx = EJBContainer.createEJBContainer().getContext();

ctx.bind("inject", this);

}

@After

public void cleanUp() throws Exception {

ctx.unbind("inject");

ctx.close();

}

あるいは

private EJBContainer ec;

@Before

public void setUp() throws Exception {

ec = EJBContainer.createEJBContainer();

ec.getContext().bind("inject", this);

}

@After

public void cleanUp() throws Exception {

ec.close();

}

Matcher API

DEMO

import static org.hamcrest.CoreMatchers.*;

import static org.hamcrest.MatcherAssert.*;

assertThat(actual, is(expected));

assertThat(actual, is(not(expected)));

assertThat(actual, is(nullValue()));

assertThat(actual, is(notNullValue()));

assertThat(actual, is(sameInstance(expected)));

assertThat(actual, is(instanceOf(Serializable.class)));

import static org.hamcrest.Matchers.*;

List<String> actual = ...;

assertThat(actual, hasItem("xxx"));

assertThat(actual, hasItems("xxx", "yyy"));

★Hamcrest matchers

assertThat(actualEmployee, is(equalToEmployee(expectedEmployee)));

public static Matcher equalToEmployee(Employee employee) {

return new EmployeeMatcher(employee);

}

private static class EmployeeMatcher extends TypeSafeDiagnosingMatcher {

private final Matcher firstName;

private final Matcher lastName;

public EmployeeMatcher(Employee employee) {

this.firstName = equalTo(employee.getFirstName());

this.lastName = equalTo(employee.getLastName());

}

@Override

protected boolean matchesSafely(Employee item, Description mismatchDescription) {

boolean matches = true;

mismatchDescription.appendText("{ ");

if (!firstName.matches(item.getFirstName())) {

mismatchDescription.appendText(" ").appendText("firstName").appendText(" ");

firstName.describeMismatch(item.getFirstName(), mismatchDescription);

matches = false;

}

if (!lastName.matches(item.getLastName())) {

mismatchDescription.appendText(" ").appendText("lastName").appendText(" ");

lastName.describeMismatch(item.getLastName(), mismatchDescription);

matches = false;

}

mismatchDescription.appendText(" }");

return matches;

}

@Override

public void describeTo(Description description) {

description.appendText("{");

description.appendText(" firstName ").appendDescriptionOf(this.firstName);

description.appendText(" lastName ").appendDescriptionOf(this.lastName);

description.appendText(" }");

}

}

NUnit

テスト対象

public class Target

{

public int Divid(int a, int b)

{

return a / b;

}

}

テストコード

using NUnit.Framework;

namespace com.example.Testers

{

[TestFixture]

class XXXTester

{

// すべてのメソッドの前処理

[TestFixtureSetUp]

public void Init()

{

// do something

}

// すべてのメソッドの後処理

[TestFixtureTearDown]

public void Dispose()

{

// do something

}

// 毎メソッドの前処理

[SetUp]

public void SetUp()

{

Target target = new Target();

}

// 正常系テストケース

[Test]

public void TestNormal()

{

Assert.AreEqual(10, target.Divid(100, 10));

}

// 異常系テストケース

[Test]

[ExpectedException(typeof(DivideByZeroException))]

// 或いは[Test, ExpectedException(typeof(DivideByZeroException))]

public void TestException()

{

target.Divid(100, 0);

}

}

}

TestNG

<dependency>

<groupId>org.testng</groupId>

<artifactId>testng</artifactId>

<version>${testng.version}</version>

<scope>test</scope>

</dependency>

@BeforeSuite/@AfterSuite テスト・スイート内ののすべてのテストが対象

@BeforeTest/@AfterTest テスト

@BeforeClass/@AfterClass テストクラス内のすべてのテストが対象

@BeforeMethod/@AfterMethod テストメソッド

@DataProvider テストメソッドにデータを供給する

@Factory オブジェクトのファクトリメソッド

@Parameters テストメソッドにパラメータを渡す

@Testの属性

dataProvider データ供給

expectedExceptions 期待する例外

groups 所属するグループ

invocationCount 実行回数

timeOut タイムアウト時間(ミリ秒)

threadPoolSize スレッドプールサイズ(invocationCountが未設定の場合、無視される)

enabled 実行可否

dependsOnMethods 依存するテストメソッド

dependsOnGroups 依存するグループ

★Execution Procedure

@BeforeSuite

@BeforeTest

@BeforeClass

@BeforeMethod

@Test

@AfterMethod

@BeforeMethod

@Test

@AfterMethod

@AfterClass

@AfterTest

@AfterSuite

testng.xml

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >

<suite name="Suite1">

<test name="test1">

<classes>

<class name="xxx"/>

</classes>

</test>

</suite>

★サンプル

テスト対象

public class MyService {

public int add(int a, int b) {

return a + b;

}

public void throwException() {

throw new RuntimeException("例外が発生しました");

}

}

テストコード

import static org.testng.Assert.*;

import org.testng.annotations.AfterClass;

import org.testng.annotations.BeforeClass;

import org.testng.annotations.BeforeMethod;

import org.testng.annotations.DataProvider;

import org.testng.annotations.Test;

public class MyServiceTest {

private MyService myService;

@BeforeClass

public static void setUpClass() {

...

}

@AfterClass

public static void tearDownClass() {

...

}

@BeforeMethod

public void init() {

myService = new MyService();

}

@Test(expectedExceptions = { RuntimeException.class })

public void testException() {

myService.throwException();

}

@DataProvider(name = "add")

public Object[][] data() {

return new Object[][] {

{ 1, 2, 3 }, { 3, 3, 6 }, { 6, 5, 11 } };

}

@Test(dataProvider = "add")

public void testAdd(int a, int b, int expected) {

assertNotNull(myService);

int actual = myService.add(a, b);

assertEquals(actual, expected);

}

@DataProvider(name = "data")

public Object[][] dataProvider() {

User user = new User();

user.setId(101);

user.setName("Andy");

return new Object[][]{

{user}

};

}

@Test(dataProvider = "data")

public void test(User user) {

...

}

@Test(timeOut=1000, invocationCount=10, threadPoolSize=5)

public void loadPerformance() throws Exception {

System.out.printf(

"%n Thread Id : %s ", Thread.currentThread().getId());

...

}

}

★Using @DataProvider and Test in Different Class

public class DataProviderClass {

@DataProvider(name = "data-provider")

public static Object[][] dataProviderMethod() {

return new Object[][] { { "one" }, { "two" } };

}

}

public class TestClass {

@Test(dataProvider = "data-provider", dataProviderClass = DataProviderClass.class)

public void testMethod(String data) {

...

}

}

★@DataProvider vs @Factory

@BeforeClass

public void beforeClass() {

out.println("beforeClass() executed");

}

@Test(dataProvider = "dataMethod")

public void testMethod(String param) {

out.println("testMethod() executed: " + param);

}

@DataProvider

private Object[][] dataMethod() {

return new Object[][] { { "one" }, { "two" } };

}

beforeClass() executed

testMethod() executed: one

testMethod() executed: two

private String param;

@Factory(dataProvider = "dataMethod")

public SampleTest(String param) {

this.param = param;

}

@DataProvider

private static Object[][] dataMethod() {

return new Object[][] { { "one" }, { "two" } };

}

@BeforeClass

public void beforeClass() {

out.println("beforeClass() executed");

}

@Test

public void testMethod() {

out.println("testMethod() executed: " + param);

}

beforeClass() executed

testMethod() executed: one

beforeClass() executed

testMethod() executed: two