3 UnitTests
djmil edited this page 2023-07-20 12:33:27 +02:00
This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

My first unit test

Let's start with the simplest thing you can imagine: a single test method with a single statement. Create src/test/java/example/cashcard/CashCardJsonTest.java:

package djmil.cashcard;

import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;

public class CashCardJsonTest {
	@Test
    public void myFirstTest() {
        assertThat(1).isEqualTo(42);
    }
}

The @Test annotation is part of the JUnit library, and the assertThat method is part of the AssertJ library. Both of these libraries are imported after the package statement.

A common convention (but not a requirement) is to always use the Test suffix for test classes. Weve done that here. The full class name CashCardJsonTest.java gives you a clue about the nature of the test we're about to write.

In true Test-First fashion, we've written a failing test first. It's important to have a failing test first so you can have high confidence that whatever you did to fix the test actually worked.

Toggle terminal with ctrl+tilda and type

./gradlew test

Testing the CashCard Data Contract

import org.springframework.boot.test.json.JacksonTester;
import org.springframework.beans.factory.annotation.Autowired;

@JsonTest
public class CashCardJsonTest {
    @Autowired
    private JacksonTester<CashCard> json;

Marking CashCardJsonTest with @JsonTest annotation makes it a test class which uses the Jackson framework (which is included as part of Spring). This provides extensive JSON testing and parsing support. It also establishes all the related behavior to test JSON objects.

@Autowired

@Autowired is an annotation that directs Spring to create an object of the requested type. JacksonTester is a convenience wrapper to the Jackson JSON parsing library. It handles serialization and deserialization of JSON objects.

To create a CashCard class and the constructor thats used in the cashCardSerializationTest() test, create the file src/main/java/djmil/cashcard/CashCard.java with the following contents (notice that this file is under in the src/main directory, not the src/test directory):

package djmil.cashcard;

public record CashCard(Long id, Double amount) {
}

The contract file

src/test/resources/djmil/cashcard/expected.json

{
  "id": 99,
  "amount": 123.45
}

NOTE Resources Pay attention to the path djmil/cashcard/ is essentially a package name. It is shared between different aspects of the project:

  • src/main/java - code
  • src/tests/java - tests
  • src/tests/resources - static resources for testing. Essentially gradle is responsible to map different parts of source code onto final package to be accessible for java via classpath.

The test

@Test
public void cashCardSerializationTest() throws IOException {
	CashCard cashCard = new CashCard(99L, 123.45);
	
	assertThat(json.write(cashCard)).isStrictlyEqualToJson("expected.json");
	
	assertThat(json.write(cashCard)).hasJsonPathNumberValue("@.id");
	assertThat(json.write(cashCard)).extractingJsonPathNumberValue("@.id")
		.isEqualTo(99);
	
	assertThat(json.write(cashCard)).hasJsonPathNumberValue("@.amount")
	assertThat(json.write(cashCard)).extractingJsonPathNumberValue("@.amount")
		.isEqualTo(123.45);
}

.isStrictlyEqualToJson("expected.json"); will try to load static file from FamilyCashCard/build/resources/test/djmil/cashcard directory.

Testing Deserialization

@Test
public void cashCardDeserializationTest() throws IOException {
	String expected = """
	{
		"id":1000,
		"amount":67.89
	}
	""";
	
	assertThat(json.parse(expected)).isEqualTo(new CashCard(1000L, 67.89));
	assertThat(json.parseObject(expected).id()).isEqualTo(1000);
	assertThat(json.parseObject(expected).amount()).isEqualTo(67.89);
}