Unit Testing

Domain driven design is intended for complex business domains, and so testing is obviously important. In this part of the tutorial we’ll cover unit testing, later on we’ll look at integration testing.

Ex 6.1: Unit test the default time when booking visits

The "Book Visit" action has a default time of 9am the next morning. In this section we’ll write a unit test to verify this logic, using Mockito to "mock the clock".

Solution

git checkout tags/06-01-unit-test-bookVisit-default-time
mvn clean install
mvn -pl spring-boot:run

Tasks

  • add test dependencies to the petclinic-module-visits maven module:

    module-visits/pom.xml
    <dependencies>
        <!-- ... -->
    
        <dependency>
            <groupId>org.apache.causeway.mavendeps</groupId>
            <artifactId>causeway-mavendeps-unittests</artifactId>
            <type>pom</type>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.jmock</groupId>
                    <artifactId>jmock-junit4</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    
    </dependencies>
  • add the test:

@ExtendWith(MockitoExtension.class)                                             (1)
class Pet_bookVisit_Test {

    @Mock ClockService mockClockService;                                        (2)
    @Mock VirtualClock mockVirtualClock;                                        (2)

    @BeforeEach
    void setup() {
        Mockito.when(mockClockService.getClock()).thenReturn(mockVirtualClock); (3)
    }

    @Nested
    class default0 {

        @Test
        void defaults_to_9am_tomorrow_morning() {

            // given
            Pet_bookVisit mixin = new Pet_bookVisit(null);
            mixin.clockService = mockClockService;                              (4)

            LocalDateTime now = LocalDateTime.of(2021, 10, 21, 16, 37, 45);

            // expecting
            Mockito.when(mockVirtualClock.nowAsLocalDateTime()).thenReturn(now);(5)

            // when
            LocalDateTime localDateTime = mixin.default0Act();

            // then
            Assertions.assertThat(localDateTime)                                (6)
                    .isEqualTo(LocalDateTime.of(2021,10,22,9,0,0));
        }
    }
}
1 Instructs JUnit to use Mockito for mocking.
2 mocks the ClockService, and mocks the VirtualClock returned by the ClockService. Automatically provisioned by Mockito.
3 makes the mock ClockService return the mock VirtualClock.
4 inject the mock clock into the domain object
5 sets up expectations for this scenario on the mock VirtualClock
6 use AssertJ to assert the expected value
Unit tests should have a suffix "_Test", to distinguish them from integration tests. The top-level pom configures Maven surefire to run the unit tests first and then integration tests as a separate execution.

Optional Exercises

If you decide to do these optional exercises, make the changes on a git branch so that you can resume with the main flow of exercises later.
  1. Write a similar unit test to verify the validation logic that visits cannot be in the past.

  2. Introduce a meta-annotation @VisitedAt, and move the validation logic into a Specification. Verify that the app still works, and write a unit test to check your specification.