It's been two years since JUnit 5 was released thus ending the incontestable rule of JUnit 4. But was this the definitive end of forth version? We are constantly encountering projects in which JUnit 4 is the only option either due to maintenance, company policies or developer habits.
Can JUnit 4 allow us to create specifications from our test code? Can we dip into property based testing and create theories about the our code? Are there any useful things that we usually don't remember about?
During the lecture, we will get acquainted with the less known features of JUnit 4 and discuss whether it is worth using them in the day to day work.
13. “So who should you be writing the
tests for? For the person trying to
understand your code. Good tests
act as documentation for the code
they are testing. They describe
how the code works.”
Gerard Meszaros
97 Things Every Programmer Should Know by Kevlin Henney
14. Given: there is no stack
When: a stack is created
Then: it is empty
15. Given: there is no stack
When: a stack is created
Then: it is has a depth of zero
16.
17.
18.
19.
20.
21.
22. Enclosed Runner
- Gives us only one level of nesting :-(
- Enclosed is a suite thus each inner static class can be run
with a different runner :-)
- Abstract inner classes are ignored thus adding an abstract
keyword can disable a test
- Shared setup (all the @Before and @After) needs to be
hidden inside an abstract class (which won’t be run)
- JUnit5 has a @Nested annotation that allows for deeper
nesting then a single level
23.
24.
25. ExpectedException Rule
- no explicit try/catch block
- it’s possible to expect an exception just before the point it
will happen, this avoids the situation where something else
throws a similar exception
- it’s possible to match part of the exception message
- deprecated in 4.13 :-(
- does not exist in JUnit 5.x :-(
- usage of Assert.assertThrows is encouraged
26.
27. TemporaryFolder Rule
- allows creating a temporary directory structure, create
files, directories etc
- can recursively create directories
- Starting with version 4.13 allows strict verification of
deleted resources which fails the test with AssertionError if
resources cannot be deleted
- only in compatibility mode in JUnit 5 :-(
28.
29. ExternalResource Rule
- Great example of such ExternalResource is
MockWebServer from okhttp
- Very useful for working with any kind of in memory
database
- Can help setup any form of dependency injection
- For sending information to some external service before
and after the test
- sky is the limit ;-)
30.
31. RuleChain
- the ordering might be important for example if we have a
rule that starts the app and closes it at the end, so if we
want to do some screenshots of the running app we need
to run the screenshot rule before the app closing rule will
finish
- when ordering is the key
- when rules depend on each other
32.
33. What we want?
- create a test that checks the depth after some amount of
operations performed on the stack
- specify the amount of push operations
- specify the amount of pop operations
- specify the expected depth of the stack
34.
35.
36.
37.
38.
39. Parametrized
- ugly syntax :-( (JUnitParams library does this better)
- we can run @Before and @After like in a normal test
- we can have more than one test method but we need
assumptions to control the values that are fed to our test
- can easily grow in size
- we need to think about all the examples beforehand
40. Can we test general properties of our code without
giving specific examples?
45. Theories
- not supported in JUnit5 but property based testing as a
concept can be done through other libraries e.g. jqwik
- can have fixed data points
- can have multiple different sources of generated values
- should probably be under smoke test category
- are not easy to define properly
46. Good Properties
- business rules as a property
- using the same input will produce the same output
- applying functions that are inverse should result with the
initial state
- doing something multiple times won’t change the result
- some operations should not change other existing
properties of the tested code/structure/class e.g. sorting
won’t change the size, filtering won’t change the order
- sometimes order of operations won’t change the result e.g.
fiter(sort) == sort(filter)