In the sixth seminar, you will write some basic tests in the codebase you are already familiar with (Employee Records).

Throughout this seminar, you will work again in cooperation with your project teammates. All of you know the procedure - form pairs.

Task 0: Update your repository

For this seminar, you will work again with the same forked repository as previously. We assume you already have the upstream remote set from Seminar 03 (if not, please follow the task 0.1 from that seminar).

Task 0.1: Update your main branch

First, you need to fetch new changes from the upstream repository and update your local main branch:

git switch main
git pull upstream main

Then you need to update the main branch in your forked repository:

git push origin main

Task 0.2: Reload Maven dependencies

Reload the Maven project in your IDE as there have been a few new dependencies added to the project, especially useful for automated testing.

In IntelliJ IDEA, there are several ways to achieve that. You can right-click on the pom.xml file in the Project tool window (on the left) and choose Maven > Reload project. Or you can use the Maven tool window (on the right) and click on the refresh icon (top left), which is the Reload All Maven Projects action.

Task 0.3: Create a new branch for this seminar

As usual, each pair creates a new branch on a single computer as they are working together as one person during the seminar.

Pair 1 creates a new branch seminar06-pair1:

git switch -c seminar06-pair1

Pair 2 creates a new branch seminar06-pair2:

git switch -c seminar06-pair2

Task 1: Examine Code Coverage

Task 1.1: Run Tests

Execute all the tests to verify they are working correctly. Feel free to use your IDE or execute them using Maven directly:

mvn clean test

Task 1.2: Run Code Coverage

You should see that all tests are passing. Although this is not a bad situation, it does not tell us much. For more information, you need to run all the tests with code coverage. To do so, you need to click on Run $TARGET with Coverage item either in the Run menu or in the toolbar.

Task 1.3: Discuss the Results

After you get the coverage results, discuss it in the pairs. Do you consider it as a sufficient coverage? What does each category of the coverage - class, method, line - tell you?

Task 2: Reach 100% Code Coverage in StringLengthValidator Unit Test

In this task, lets focus on the StringLengthValidator. The provided unit tests cover only 80 % of the code.

In Java, basic unit tests can be written using JUnit with a little help from other libraries such as AssertJ. Simply place assertThat(expression) followed by a cascade of certain assertions such as isEqualTo, contains, or isLessThan (there are plenty of them).

Task 2.1: Write More Tests

Design and write additional tests to reach the 100 % Code Coverage of the StringLengthValidator class. Discuss the test design with your partner in advance of writing the test. We will get back to your conclusions in the reflection part at the end of seminar.

When you are done with this task, do not forget to commit and push your changes.

Task 3: Test all methods of the EmployeeCrudService

In this task, we want you to improve the code coverage of EmployeeCrudService. Even though the overall code coverage tells us only one method is not tested (update), the deleteAll method is not tested either. You can try to figure out why Idea “is telling lies to you”. Your task is to test both update and deleteAll methods and achieve the 100 % code coverage. Preferable, for each branching create a new test.

To write tests of more complex class with dependencies, the developer needs to somehow provide these dependencies to the tested class. There are two straightforward options how to achieve this - manually crafted test doubles or objects provided by libraries such as Mockito using a kind of magic. We will use the second one. Both options can be used if all the dependencies are referenced via interfaces and if all the dependencies are passed from the outside via dependency injection. These restrictions are fulfilled in case of EmployeeCrudService.

Task 3.1: Write update tests

To write update tests, start by studying create* tests for a while. First, you need to define the behavior of the dependencies such as “if method A is called, B should be returned”. Then run the code you want to test. After that, you should examine the results of the execution. Use assertions to test the results and expected outcomes, as in the previous task. Use verify-cations if you want to test how many times some method was executed (or whether it was not executed at all).

Task 3.2: Write deleteAll test

To write the deleteAll test, it should be easy to use a similar approach to deleteById test.

Again, commit and push your changes when you are done.

Task 4: Test multiple Employee export

In previous tasks, you wrote unit tests. This time, you will write an integration test. The main difference is that previously you have called just one method of a class. In case that the method required a dependency, you have provided a fake one. In the integration test the fully assembled class/package/module/… is expected, with all necessary dependencies. In this kind of tests, you are interested in the behavior of the whole (part of the) system.

Task 4.1: Inspect setUp

Look at how the whole environment for the GenericImportServiceIntegrationTest is assembled. Compare it with the constructor of MainWindow. Is it similar?

Task 4.2: Write exportMultipleEmployees test

Write test which results in exporting more than just a one employee into a CSV file.

Again, commit and push your changes when you are done.

Task 5: Test Multiple Employee Import

Similarly to the previous task, you will write integration tests, this time regarding the importing of CSV files. However, the approach should be slightly different. When you design a test of some output producing part of the system, you mainly focus on the functionality and the output format or the protocol. That said - you are testing “the happy paths”.

When you design a test of some input consuming part of the system, while it is definitely useful to have some “happy paths” tests, it is still not sufficient. You must focus on a broken input scenarios on a variety of levels. Anything from invalid format to data duplication can compromise the system and cause a real damage. That is why you should be creative.

Task 5.1: Write Import Tests

Each test should focus on some aspect of wrong input. Discuss that with your partner in advance. In this task, we do not want to limit your creativity. In the reflection, we will be happy to hear your different approaches.

Again, commit and push your changes when you are done.