LAB6 Dynamic Verification Techniques

Integration and Verification Techniques (VIMIAC04)

Note: Please treat these exercises also as professional work. For example, instead of "asdfg" use more meaningful commit messages like "Add acceleration feature" or "Fix #5" (you can find detailed advice in the How to Write a Git Commit Message and the Git Style Guide posts).

Introduction

In case of dynamic verification techniques the source code under verification is executed. Dynamic verification techniques include software testing, which is applicable on all levels of the development process. The lowest level is unit testing, which is performed during or right after the code is implemented.

Use your version of the Spaceship project extended in the previous labs. The goal of the current lab is to test the GT4500 class iteratively.

Isolating the unit under test

During previous labs you could have seen instable tests, i.e. same tests sometimes passing and later failing. In the current project this is because the TorpedoStore class is non-deterministic. Therefore our first step should be to isolate this erratic dependency from our unit under test, GT4500. Calls to TorpedoStore should be replaced with calls to test doubles (stubs, mocks...). We will use the Mockito framework to accomplish this.

  1. Extend the GT4500 class in order to be able to inject its dependencies (see dependency injection).
  2. Extend the init method of the existing GT4500Test test that test doubles could be used instead of real instances of TorpedoStore. You can create test double using the mock method of Mockito.
  3. Execute the existing two tests. What happens? Define the necessary behavior for the mocks according to each tests' purpose. Rerun your test cases.
  4. Refactor your tests to check interactions and not state (verify Mockito method).

Below you can find a simple example from an other project showing how Mockito can be used. Check out the documentation of Mockito for more details.

public class PriceServiceTest {
    private DataAccess mockDA;
    private PriceService ps;

    @Before public void init() {
        // Create mock for the dependency DataAccess
        mockDA = mock(DataAccess.class);
        ps = new PriceService(mockDA);
    }

    @Test public void SuccessfulPriceQuery() {
        // Arrange
        // Set the behavior of the mock: if it is called with
        //  parameter "A100" then return the value 50.
        when(mockDA.getProdPrice("A100")).thenReturn(50);

        // Act
        ps.getPrice("A100");

        // Assert
        // Verifying the mock: getProdPrice was called only once
        verify(mockDA, times(1)).getProdPrice("A100");
    }

}

Test design

When designing unit tests three approaches can be used:

Design at least 5 test cases for the fireTorpedo method of the GT4500 class based on the specification in the JavaDoc comment of the method. Use only the method comment and not the source code. Document the test cases in a text or spreadsheet file.

Implementing test cases

  1. Implement your new test cases using JUnit 5. Use mocks for TorpedoStore in your test cases. Try to verify state and interaction also (see here)!
  2. Design and implement one more new test case based only on the source code. What is the downside of this approach?

Measuring code coverage

During unit testing measuring the coverage of the tests provides continuous, actionable feedback. There are tools in ever major programming language. In case of Java the most frequently used tools include: JaCoCo, Cobertura, Clover.

We will use JaCoCo tool, which is available as a Maven plugin. To use it, add the following to fragments to the pom.xml file.

<dependency>
  <groupId>org.jacoco</groupId>
  <artifactId>jacoco-maven-plugin</artifactId>
  <version>0.8.7</version>
  <scope>test</scope>
</dependency>
<plugin>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>0.8.7</version>
    <executions>
        <execution>
            <id>default-prepare-agent</id>
            <goals>
                <goal>prepare-agent</goal>
            </goals>
        </execution>
        <execution>
            <id>default-report</id>
            <phase>prepare-package</phase>
            <goals>
                <goal>report</goal>
            </goals>
        </execution>
    </executions>
</plugin>
  1. Measure the code coverage of your existing tests using JaCoCo! Run your tests with mvn verify to have code coverage results.
  2. The report can be found in the /target/site/jacoco folder. Open the index.html and navigate to the tested method. Take note of the uncovered lines.
  3. Extend your tests if they have less than 100% instruction or branch coverage.

Further information