This entry is for GMO Ad Marketing Advent Calendar 2018 (Https://qiita.com/advent-calendar/2018/gmo-am) [12/09] article. This is the first GMO ad marketing entry in the Advent Calendar.
In Go language, it is common to write test code in the form of Table Driven Test. The word "Go-ness" is often used among Go engineers. The source code is always required to be written like Go. I think there are some ambiguities in the word Go-ness, but Table Driven Test is one of Go's uniqueness. This time, I will introduce an example of bringing Go-ness to Java.
The Table Driven Test is described on the following pages. https://github.com/golang/go/wiki/TableDrivenTests
In Table Driven Test, test cases are represented by a structure, which is looped to execute the test. This time, for the sake of explanation, I created a partial test of pow.go.
package main
import (
"testing"
"math"
)
func TestPow(t *testing.T) {
for _, tt := range []struct {
name string
x float64
y float64
expected float64
}{
{"Pow(2,1)", 2, 1, 2},
{"Pow(2,2)", 2, 2, 4},
{"Pow(2,3)", 2, 3, 8},
{"Pow(2,0)", 2, 0, 1},
{"Pow(2,-1)", 2, -1, 0.5},
{"Pow(0,2)", 0, 2, 0},
{"Pow(2,+Inf)", 2, math.Inf(0), math.Inf(0)},
{"Pow(2,-Inf)", 2, math.Inf(-1), 0},
{"Pow(+Inf,2)", math.Inf(0), 2, math.Inf(0)},
{"Pow(-Inf,2)", math.Inf(-1), 2, math.Inf(0)},
} {
t.Run(tt.name, func(t *testing.T) {
result := math.Pow(tt.x, tt.y)
if result != tt.expected {
t.Errorf("expected: %v, result: %v", tt.expected, result)
}
})
}
}
In this example, the structure defines the test name, method arguments, and expected value. By writing like this, what each value represents It also makes it easier to see what you are testing.
Use the features added in JUnit 5 to implement Table Driven Test in Java.
This time I created a pow test for the Math class. The example uses lombok to keep the source code simple.
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.experimental.Accessors;
import org.junit.jupiter.api.*;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.assertEquals;
class MathTest {
@Nested
static class Pow {
@AllArgsConstructor
@Getter
@Accessors(fluent = true)
static class TestCase {
private String name;
private double x;
private double y;
private double expected;
}
@TestFactory
Stream<DynamicNode> testPow() {
return Stream.of(
new TestCase("pow(2,1)", 2, 1, 2),
new TestCase("pow(2,2)", 2, 2, 4),
new TestCase("pow(2,3)", 2, 3, 8),
new TestCase("pow(2,0)", 2, 0, 1),
new TestCase("pow(2,-1)", 2, -1, 0.5),
new TestCase("pow(2,+Inf)", 2, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY),
new TestCase("pow(2,-Inf)", 2, Double.NEGATIVE_INFINITY, 0),
new TestCase("pow(+Inf,2)", Double.POSITIVE_INFINITY, 2, Double.POSITIVE_INFINITY),
new TestCase("pow(-Inf,2)", Double.NEGATIVE_INFINITY, 2, Double.POSITIVE_INFINITY)
).map(testCase -> DynamicTest.dynamicTest(
testCase.name(),
() -> {
double result = Math.pow(testCase.x(), testCase.y());
assertEquals(testCase.expected(), result);
})
);
}
}
}
In JUnit 5, you can define an inner class with @ Nested
to nest your tests.
In this example, the test is defined by an inner class called Pow.
In Pow, we define an inner class called TestCase. The TestCase fields define the test name, the arguments to pass to the method, and the expected result. The value used in each test case is passed in the TestCase constructor.
If you use a class like Tuple here, It's hard to tell what each value you pass to Tuple represents, By having the test case in an inner class like the example You can associate a value with a named field.
We use JUnit 5's new Dynamic Tests (https://junit.org/junit5/docs/current/user-guide/#writing-tests-dynamic-tests) to run the tests.
@testfactory
By attaching to a method that returns a dynamic node stream, collection, etc.
You can run the test dynamically.
By combining the features of JUnit 5 with the goodness of Go language, I was able to write a highly readable test in Java. It would be great if we could continue to incorporate the good points of other languages, such as Go-ness, into Java.
GMO Advent Calendar 2018 that lasts until Christmas Stay tuned for more posts!
■ Techblog by engineers is now available! https://techblog.gmo-ap.jp/ ■ Wantedly page-Blogs and job offers are now available! ~ https://www.wantedly.com/projects/199431 ■ Engineer recruitment page-Click here for information on benefits and various systems- https://www.gmo-ap.jp/engineer/ ■ Recruiting engineer student internships! -Experience the development site with a paid intern- https://hrmos.co/pages/gmo-ap/jobs/0000027
Recommended Posts