Warning: This may be a bit much for week 1 feel free to skip this theory, and come back to this later.
The JUnit framework provides a number of annotations to structure
your test classes. The basic one is of course @Test
but as your
skills in testing increase you may want to design your tests in a
more sophisticated way.
Annotations represent notes in your code that make your intentions clear:
@Override
@Test
To indicate that a method is intended as a unittest. The @Test
annotation is
added. From this test function other (non-test) functions may be called. But
this annotation adds the method to the list of tests.
When designing tests please apply the following rule of thumb:
Note: Each test method should test one single concept. Although a test may contain multiple asserts to confirm that single concept.
Note: There is no guarantee about the order in which tests are executed!
As your tests become more complex, you may notice that all of your test functions start with the same code fragment to create a data structure instance against which you will perform your tests.
In that case the annotation @BeforeEach
will mark one of your methods
as the one that is executed before every test.
You may also have some code that needs to be executed in order to cleanup
your test. A similar annotation exists for that: @AfterEach
You may go one step further when you are using a resource that is rather
expensive to use: @BeforeAll
and @AfterAll
You may use this to connect to the test database, then to all the tests, and finally close the connection to the database.
Or your tests may require a set of csv files to work with. Then during the test additional output files may be created. And finally you may want to delete your directory with test results when you’re done.
Your data structure setup must never be defined in a ‘@BeforeAll’ method. Remember that tests are not called in a guaranteed order. So any changes to this structure influence the other tests.
Data structure setup must occur before each (`@BeforeEach) test so that each test starts with the exact same structure.
The same idea goes for after each and after all.
In general @BeforeAll
and @AfterAll
are used to configure
communication channels to remote systems or a database.
Sometimes you may want to run a test multiple times with various values.
Note: I said Various Values not Random Values. Tests must always result in the same answer.
When using a random number generator, always initialise it with the same seed value.
A test that fails only on mondays is a Very Bad Test. So a test that fails for certain random values should be avoided. When any random value is legal, you should still be careful.
Actual reasons for doing this:
A parameterized test will repeatedly run a test while looping through the set of values you provided:
@ParameterizedTest
@ValueSource(ints = {1, 3, 5, -3, 15, Integer.MAX_VALUE}) // six numbers
void isOdd_ShouldReturnTrueForOddNumbers(int number) {
assertTrue(Numbers.isOdd(number));
}
(Taken from Bealdung.com)
In this example a set of numbers need to be tested. To do that both annotations are required. One indicates that the test will be repeated with a certain parameter. The second provides a stream of values. (In this case integers.)