DartとJavaの単体テストを比較

unittestの使い方をJUnitと比較しながら整理してみました


## 実行環境
* Dart 1.1.1
* unittest 0.10.0
* Java 1.7.0
* JUnit 4.11.0


## テスト対象のクラス
**Dart**

```dart:calc.dart
library clac;

class Calc {
  int add(int x, int y) {
    return x + y;
  }
  int sub(int x, int y) {
    return x - y;
  }
}
```

**Java**

```java:Calc.java
package main.unittest;

public class Calc {
	public int add(int x, int y) {
		return x + y;
	}
	public int sub(int x, int y) {
		return x - y;
	}
}
```


## 基本形
*example02_test.dart* のようにも書ける

**Dart**

```dart:example01_test.dart
library example01;

import 'calc.dart';
import 'package:unittest/unittest.dart';

void main() {
  test("add test", () {
    Calc calc = new Calc();
    int expected = 5;
    int actual = calc.add(3, 2);
    expect(actual, equals(expected));
  });
  
  test("sub test", () {
    Calc calc = new Calc();
    int expected = 1;
    int actual = calc.sub(3, 2);
    expect(actual, equals(expected));
  });
}
```

```dart:example02_test.dart
library example02;

import 'calc.dart';
import 'package:unittest/unittest.dart';

void main() {
  TestFunction testAdd = () {
    Calc calc = new Calc();
    int expected = 5;
    int actual = calc.add(3, 2);
    expect(actual, equals(expected));
  };

  TestFunction testSub = () {
    Calc calc = new Calc();
    int expected = 1;
    int actual = calc.sub(3, 2);
    expect(actual, equals(expected));
  };
  
  test("add test", testAdd);
  test("sub test", testSub);
}
```

**Java**

```java:Example01.java
package test.unittest;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import main.unittest.Calc;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

@RunWith(JUnit4.class)
public class Example01 {
	@Test
	public void addTest() {
		Calc calc = new Calc();
		int expected = 5;
		int actual = calc.add(3, 2);
		assertThat(actual, is(expected));
	}
	
	@Test
	public void subTest() {
		Calc calc = new Calc();
		int expected = 1;
		int actual = calc.sub(3, 2);
		assertThat(actual, is(expected));
	}
}
```


## グループ化
Dartでは *group* メソッドを用いる

**Dart**

```dart:example03_test.dart
library example03;

import 'calc.dart';
import 'package:unittest/unittest.dart';

void main() {  
  group("Group Add", () {
    test("add test1", () {
      Calc calc = new Calc();
      int expected = 5;
      int actual = calc.add(3, 2);
      expect(actual, equals(expected));
    });
    
    test("add test2", () {
      Calc calc = new Calc();
      int expected = 1;
      int actual = calc.add(3, -2);
      expect(actual, equals(expected));
    });
  });
  
  group("Group Sub", () {
    test("sub test1", () {
      Calc calc = new Calc();
      int expected = 1;
      int actual = calc.sub(3, 2);
      expect(actual, equals(expected));
    });
  });
}
```

**Java**

```java:Example03.java
package test.unittest;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import main.unittest.Calc;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.experimental.runners.Enclosed;

@RunWith(Enclosed.class)
public class Example03 {
	public static class GroupAdd {
		@Test
		public void addTest1() {
			Calc calc = new Calc();
			int expected = 5;
			int actual = calc.add(3, 2);
			assertThat(actual, is(expected));
		}
		
		@Test
		public void addTest2() {
			Calc calc = new Calc();
			int expected = 1;
			int actual = calc.add(3, -2);
			assertThat(actual, is(expected));
		}
	}
	
	public static class GroupSub {
		@Test
		public void subTest() {
			Calc calc = new Calc();
			int expected = 1;
			int actual = calc.sub(3, 2);
			assertThat(actual, is(expected));
		}
	}
}
```


## フェーズ
アノテーションを使用する代わりに、Dartでは *setUp* や *tearDown* メソッドを用いる
テストをスキップしたい場合は *skip_test* メソッドを使う

**Dart**

```dart:example04_test.dart
library example04;

import 'calc.dart';
import 'package:unittest/unittest.dart';

void main() {
  Calc calc;
  
  setUp(() {
    print("set up");
    calc = new Calc();
  });
  
  tearDown(() {
    print("tear down");
  });
  
  test("add test1", () {
    int expected = 5;
    int actual = calc.add(3, 2);
    expect(actual, equals(expected));
  });
  
  skip_test("add test2", () {
    int expected = 1;
    int actual = calc.add(3, -2);
    expect(actual, equals(expected));
  });
  
  test("sub test1", () {
    int expected = 1;
    int actual = calc.sub(3, 2);
    expect(actual, equals(expected));
  });
}
```

**Java**

```java:Example04.java
package test.unittest;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import main.unittest.Calc;

import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

@RunWith(JUnit4.class)
public class Example04 {
	Calc calc;
	
	@Before
	public void setUp() {
		System.out.println("set up");
		calc = new Calc();
	}
	
	@After
	public void tearDown() {
		System.out.println("tear down");
	}
	
	@Test
	public void addTest1() {
		System.out.println("add test1");
		int expected = 5;
		int actual = calc.add(3, 2);
		assertThat(actual, is(expected));
	}
	
	@Ignore
	public void addTest2() {
		System.out.println("add test2");
		int expected = 1;
		int actual = calc.add(3, -2);
		assertThat(actual, is(expected));
	}
	
	@Test
	public void subTest() {
		System.out.println("sub test");
		int expected = 1;
		int actual = calc.sub(3, 2);
		assertThat(actual, is(expected));
	}
	
}
```


## Matcher
JUnitと似たようなMatcherがDartにも用意されている

**Dart**

```dart:example05_test.dart
library example05;

import 'calc.dart';
import 'package:unittest/unittest.dart';

void main() {
  test("fail", () {
    Calc calc = new Calc();
    int expected = 5;
    int actual = calc.add(3, 2);
    fail("fail");
    expect(actual, equals(expected));
  });
  
  test("matchers", () {
    int actual = 1;
    expect(actual, equals(1));
    expect(actual, isNot(0));
    expect(actual, same(1));
    expect(actual, new isInstanceOf<int>());
    
    expect(actual, isNull);
    expect(actual, isNotNull);
  });
}
```

**Java**

```java:Example05.java
package test.unittest;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.sameInstance;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import main.unittest.Calc;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

@RunWith(JUnit4.class)
public class Example05 {
	@Test
	public void failTest() {
		Calc calc = new Calc();
		int expected = 5;
		int actual = calc.add(3, 2);
		fail("fail");
		assertThat(actual, is(expected));
	}
	
	@Test
	public void matchersTest() {
		int actual = 1;
		assertThat(actual, is(1));
		assertThat(actual, is(not(0)));
		assertThat(actual, is(sameInstance(1)));
		assertThat(actual, is(instanceOf(Integer.class)));
		
		assertThat(actual, is(nullValue()));
		assertThat(actual, is(notNullValue()));
	}
}
```


## 例外送出
JUnitではTestアノテーションに指定するが、Dartでは *expect* メソッドで検証する

**Dart**

```dart:example06_test.dart
library example06;

import 'package:unittest/unittest.dart';

void main() {
  test("exception", () {
    expect(()=> throw new Exception("exception"), throwsException);
  });
}
```

**Java**

```java:Example06.java
package test.unittest;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

@RunWith(JUnit4.class)
public class Example06 {
	@Test(expected = Exception.class)
	public void exceptionTest() throws Exception {
		throw new Exception();
	}
}
```


## テストランナー
複数のテストクラスをまとめて実行する

**Dart**

```dart:example07_test.dart
library example07;

import 'example01_test.dart' as example01;
import 'example03_test.dart' as example03;
import 'example04_test.dart' as example04;

void main() {
  example01.main();
  example03.main();
  example04.main();
}
```

**Java**

```java:Example07.java
package test.unittest;

import org.junit.runner.RunWith;
import org.junit.runners.Suite;

@RunWith(Suite.class)
@Suite.SuiteClasses({
	Example01.class,
	Example03.class,
	Example04.class,
})

public class Example07 {}
```


## 参考
* [Unit Testing with Dart](https://www.dartlang.org/articles/dart-unit-tests/index.html)

* [unittest library](https://api.dartlang.org/apidocs/channels/stable/#unittest/unittest)