官术网_书友最值得收藏!

Requirement 1 – placing pieces

We should start by defining the boundaries and what constitutes an invalid placement of a piece.


A piece can be placed on any empty space of a 3×3 board.

We can split this requirement into three tests:

  • When a piece is placed anywhere outside the x-axis, then RuntimeException is thrown
  • When a piece is placed anywhere outside the y-axis, then RuntimeException is thrown
  • When a piece is placed on an occupied space, then RuntimeException is thrown

As you can see, the tests related to this first requirement are all about validations of the input argument. There is nothing in the requirements that says what should be done with those pieces.

Before we proceed with the first test, a brief explanation of how to test exceptions with JUnit is in order.

Starting from Release 4.7, JUnit introduced a feature called Rule. It can be used to do many different things (more information can be found at https://github.com/junit-team/junit/wiki/Rules), but in our case we're interested in the ExpectedException rule:

public class FooTest {
  @Rule
  public ExpectedException exception = ExpectedException.none();
@Test public void whenDoFooThenThrowRuntimeException() { Foo foo = new Foo(); exception.expect(RuntimeException.class); foo.doFoo(); } }

In this example, we defined that the ExpectedException is a rule. Later on, in the doFooThrowsRuntimeException test, we're specifying that we are expecting the RuntimeException to be thrown after the Foo class is instantiated. If it is thrown before, the test will fail. If the exception is thrown after, the test is successful.

@Before can be used to annotate a method that should be run before each test. It is a very useful feature with which we can, for example, instantiate a class used in tests or perform some other types of actions that should be run before each test:

private Foo foo; 

@Before 
public final void before() { 
  foo = new Foo(); 
} 

In this example, the Foo class will be instantiated before each test. This way, we can avoid having repetitive code that would instantiate Foo inside each test method.

Each test should be annotated with @Test. This tells JunitRunner which methods constitute tests. Each of them will be run in a random order so make sure that each test is self-sufficient and does not depend on the state that might be created by other tests:

@Test 
public void whenSomethingThenResultIsSomethingElse() { 
  // This is a test method 
} 

With this knowledge, you should be able to write your first test and follow it with the implementation. Once done, compare it with the solution provided.

Use descriptive names for test methods. 

One of the benefits is that it helps to understand the objective of tests.

Using method names that describe tests is beneficial when trying to figure out why some tests failed or when the coverage should be increased with more tests. It should be clear what conditions are set before the test, what actions are performed, and what the expected outcome is.

There are many different ways to name test methods. My preferred method is to name them using the given/when/then syntax used in BDD scenarios. Given describes (pre)conditions, When describes actions, and Then describes the expected outcome. If a test does not have preconditions (usually set using the @Before and @BeforeClass annotations), Given can be skipped.

Do not rely only on comments to provide information about test objectives. Comments do not appear when tests are executed from your favorite IDE, nor do they appear in reports generated by the CI or build tools.

Besides writing tests, you'll need to run them as well. Since we are using Gradle, they can be run from the command prompt:

    $ gradle test

IntelliJ IDEA provides a very good Gradle tasks model that can be reached by clicking on View|Tool Windows|Gradle. It lists all the tasks that can be run with Gradle (test being one of them).

The choice is yours—you can run tests in any way you see fit, as long as you run all of them.

主站蜘蛛池模板: 客服| 乃东县| 临漳县| 临西县| 雷波县| 饶阳县| 昭通市| 桐庐县| 雅江县| 连山| 梅河口市| 高青县| 宜君县| 包头市| 赤壁市| 永平县| 黄大仙区| 宁武县| 南平市| 茂名市| 自治县| 叙永县| 广州市| 远安县| 江西省| 绥棱县| 中山市| 东明县| 寿宁县| 响水县| 舒城县| 张家口市| 大埔区| 芒康县| 县级市| 舟山市| 肇州县| 聂拉木县| 武穴市| 屏边| 射洪县|