# Writing your first test in Dart

Writing tests in Dart is super easy. Everything you need to get started you get right out of the box. Every Dart (and Flutter) project comes with an example test to get you started.

*This article is the fourth in the [Introduction to TDD](https://fluttergamedev.com/series/introduction-to-tdd) series in which we are creating a Tic Tac Toe logic package using Test Driven Development.*

In the [previous article](https://fluttergamedev.com/defining-a-public-api-for-your-dart-package) we've defined the following API for our package: 

```dart
enum Player { one, two }

enum Status { p1Turn, p2Turn, p1Win, p2Win, draw }

abstract class TicTacToeGameState {

  List<Player?> get fields;
  Status get status;

  TicTacToeGameState claimField(int index);
}
```

In this article we will write our first test and implement the corresponding code to make the test pass.

# Structuring the tests

We will separate our tests from our implementation code by putting them in a separate directory.

The `test` directory, which was generated when we created the project, already contains an example test. We won't be using this file, so it can be deleted. We will add our new test file to this test directory.

It's common practice to *mirror* the files under the `src` directory for the test files. So when we have a file under `src`, we will have a corresponding test file under `test`. For better distinguishing the implementation files from the test files we end test files with `test.dart`.

For our case it would look like this:

```
/lib
  /src
    /tic_tac_toe_game_state.dart // game state implementation
  /tic_tac_toe_game.dart // the library file
/test
  /tic_tac_toe_game_state_test.dart // game state tests

```

# Our first test

In the very [first article](https://fluttergamedev.com/what-is-test-driven-development) of this series I suggested to start with the *low hanging fruits*. These are the tests that require the least effort, like getter-fields and (simple) constructors.

## Covering our first requirement

In the second article of the series ([Preparing for development](https://fluttergamedev.com/preparing-for-development)) we've listed the rules of Tic Tac Toe. One of these rules is: 

> The game is played on a three-by-three grid (starts out empty).

So initially, when we create a new game state, `fields` should return a list containing nine (three times three) *empty* fields. We can write a test for this!

## Testing the initial game state

It has been decided. We are going to test the initial state of the game by writing a test that expects a list of nine empty fields. 
The test will look like this:

```dart
void main() {
  group(
    'fields',
    () {
      test(
        'initial state should return 9 empty fields',
        () {
          final gameState = TicTacToeGameState();

          expect(
            gameState.fields,
            <Player?>[null,null,null,null,null,null,null,null,null],
          ); 
        },
      );
    },
  ); 
}
```

We've created a group named 'fields' for the property that we are testing. Grouping tests is useful because it allows you to run all the tests for the thing you are currently working on.

Then we create the `test` with a descriptive name about what we are expecting. The test itself is rather simple. We create a new instance of `TicTacToeGameState` and then check if the `fields` property returns the expected value (a list of nine `null` values).

However, we are not able to run this test yet, since we can't instantiate an *abstract class*, which `TicTacToeGameState` currently is.

## Writing the implementation

To make the test able to run and pass we have to start writing the implementation. Some people prefer to write the implementation logic as a new class and make that new class *implement* the interface.

In our case I think that's a little bit overkill, so we're going to change our *abstract class* into a regular class. We do this by simply removing the `abstract` keyword.

```dart
enum Player { one, two }

enum Status { p1Turn, p2Turn, p1Win, p2Win, draw }

class TicTacToeGameState {

  List<Player?> get fields;
  Status get status;

  TicTacToeGameState claimField(int index);
}
``` 

Now your IDE will probably complain that you have to implement the *getters* and the *function*. Since we only care about the `fields` getter for our first test, and the rule is to write as little implementation as possible to make the test pass, we can end up with the following:

```dart
enum Player { one, two }

enum Status { p1Turn, p2Turn, p1Win, p2Win, draw }

class TicTacToeGameState {

  List<Player?> get fields => [null,null,null,null,null,null,null,null,null];
  Status get status => throw 'not implemented';

  TicTacToeGameState claimField(int index) => throw 'not implemented';
}
```

We made `fields` return exactly what is expected from the test, a list of nine `null` values. The others just throw a 'not implemented' message for now just to keep the compiler happy. They won't cause a problem since they won't be called yet.

## Running the test

Now that we have written our first implementation, we can run the test to see if it passes.

Most of the IDE's like VScode and Android Studio have the ability to run the tests directly from code and show the results in a nice UI. I will use the Dart commands in the terminal to stay IDE independent. Let's give it a try!

```
$ dart test 
00:01 +1: All tests passed! 
```

Running `dart test` (or `flutter test`) will make Dart discover all the tests and run them. In our case the test passes, since we return exactly what was expected by the test.

Great job, but we can do more!

# Adding another test

Our `fields` getter doesn't do much, and what it does, we've tested. But, there is one more test that we can write that can be of great value.

## Protecting the property

When the consumer of our package *gets* the `fields` from a `TicTacToeGameState` it is meant to be used for representing the current state. The return type of `fields` is a `List`, and a `List` in Dart has functions to `add` and `remove` items.

This is a problem, because this means that the consumer could try to bypass our `claimField` function by updating the `fields` directly.
Let's first write the test for this *problem*:

```dart
test(
  'changing the returned list should not alter the inner state',
  () {
    final gameState = TicTacToeGameState();

    gameState.fields[0] = Player.one;

    expect(
      gameState.fields,
      [null, null, null, null, null, null, null, null, null],
    );
  },
);
```

The test is almost the same as our first. With the only difference that in this test we're trying to alter the `fields` directly by setting the first entry to `Player.one`. We expect this to have no effect.

## Running our second test

Now we're going to run the test to see if it fails. We will run the `dart test` command with the `name` parameter so we will only run the test we are currently working on.

```
$ dart test --name="changing the returned list should not alter the inner state"
00:01 +1: All tests passed! 
```

Wait what?! It passed? Well, it does make sense if we take a look at our implementation. `fields` currently returns an empty `List` every time it gets called. So yeah, our test passes because the second time we *get* `fields` we get a different one than the one we've just tried to manipulate.

Just because we didn't have to write any new code to make the test pass, doesn't mean this test is useless. Code can be refactored in the future so we've now secured it for possible future changes, well done!

# What's next?

We've now covered `fields` with two tests. The first checks if the initial value returns the expected value and the second checks if we're not able to alter the `fields` directly.

In the next article we will continue with the other property, `status`.  We are going to have to find a way to create different *states* without actually playing the game to be able to test all the different outcomes.

In the next article I will show you how you could do that!

**Next article: **[coming soon](https://fluttergamedev.com/writing-your-first-test-in-dart)

