Rework JUnit developer guide
[docs.git] / docs / developer-guides / tests / junit.rst
1 #############################
2 Build Time Testing with JUnit
3 #############################
4
5
6
7 Introduction to JUnit
8 =====================
9
10 JUnit is a framework for writing build time tests.
11 See their home page http://junit.org/ for more information.
12
13 Build time tests are tests which run during the compilation phase of
14 your project. Build time tests provide a way for a developer to quickly
15 test (in isolation) the logic which belongs to a given project to verify
16 it is behaving as desired.
17
18 Below we will provide the basics of JUnit tests and how you can use them,
19 along with recommendations of how to write JUnit tests.
20
21 Additionally JUnit integrates nicely with the Eclipse and Idea frameworks
22 to provide launching and debugging unit tests from within the IDE framework.
23
24 Qualities of a Good Unit Test
25 =============================
26
27 A good unit test will:
28
29 #. Run quickly
30
31    -  No sleeps or thread blocking if you can avoid it
32
33 #. Run against the public API's of a class (think interfaces!)
34 #. Test a "single" unit of work
35
36    -  Unit tests generally test an isolated piece of functionality.
37       Integration tests are used to test the interaction between two
38       pieces of logic.
39    -  You can have multiple tests in a single test class, each testing a
40       different piece of functionality... more on that later.
41
42 #. Contain assertions which validate the functionality
43
44 To help get an idea if you tested all of your code you can use Code
45 Coverage tools to review your code coverage. One such tools is `EclEmma <https://www.eclemma.org>`__
46 for eclipse which provides a mechanism to visually report the code coverage of
47 or more unit tests.
48
49 Running a JUnit Test
50 ====================
51
52 Command Line
53 ~~~~~~~~~~~~
54
55 To run a JUnit tests via the command line you only need to run:
56
57 ``mvn test``
58
59 However, that only runs the tests, it doesn't recompile them. In general
60 running
61
62 ``mvn clean install``
63
64 is the best way as it rebuilds your bundle and then executes any JUnit
65 tests.
66
67 Eclipse
68 ~~~~~~~
69
70 To run a JUnit tests via Eclipse, you can select the method, class,
71 package, or source folder, right click it, and select *"Run As" -> "JUnit
72 Test"*. The JUnit tests will now execute and an overview can bee seen in
73 the JUnit view.
74
75 Debugging a Test
76 ================
77
78 To debug a JUnit test via Eclipse, simply place your breakpoints as
79 expected, and then right click the test method and choose *"Debug As" ->
80 "JUnit Test"*. The test will start and will pause when the breakpoint is
81 hit.
82
83 Example Implementation
84 ======================
85
86 Below we provide an example of how you can implement a JUnit test in
87 your code.
88
89 Test Name and Package
90 ~~~~~~~~~~~~~~~~~~~~~
91
92 A few things to keep in mind when creating a JUnit test class:
93
94 -  Your JUnit test **MUST** start with, or end with the word **Test**.
95    This is a keyword that the command line maven test invocation
96    strategy looks for when deciding if it should inspect a class for
97    JUnit annotations. If you class does not start or end with the word
98    test it will NOT run via the maven command line and therefore will
99    not run during builds either (however you will be able to invoke it
100    via eclipse).
101 -  It is best practice to place the JUnit test in the same package as
102    the class that you are testing. This makes it easier to find the
103    corresponding tests as well provides access to default members or
104    methods if needed.
105 -  You should try and name your class similar to the class under test
106    (often just appending to the end the word "test" or if you have
107    multiple test files, then appending a description of each file to the
108    end of the file).
109
110 Adding JUnit to your Maven Project
111 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
112
113 To add the JUnit dependency to your maven project you simply add this
114 dependency into the dependencies section of your pom file.
115
116 .. code:: xml
117
118    <dependency>
119      <groupId>junit</groupId>
120      <artifactId>junit</artifactId>
121      <version>4.8.1</version>
122      <scope>test</scope>
123    </dependency>
124
125 .. note::
126    You can exclude the scope and version tags assuming a parent
127    project has defined the dependency in the dependency management
128    section.
129
130 Creating your Test Class - Annotations
131 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
132
133 A JUnit test class is simply a java class. We use java annotations to
134 mark the methods which set up the test and those which define actually
135 tests.
136
137 In order to write a good unit test it is important to understand how
138 JUnit executes your tests. JUnit will instantiate a new instance of your
139 test class for each test method (@Test) that is defined in your test class.
140 This means that non static class variables will be unique per instance of test
141 method.
142 This is done to ensure that one test method doesn't unintentionally interfere
143 with another test in the same class.
144 Unfortunately this also means that you need to initialize common intelligence
145 every time which may lead to longer running tests (or messy code)
146 which is something we want to avoid.
147 JUnit makes this easier with a few additional annotations.
148 Below is the flow of a JUnit test test:
149
150 #. **@BeforeClass** - This annotation can appear once in a test class on
151    a public *static* method which takes no arguments. This provides a
152    way to initialize some test data for ALL test methods in your test
153    class. A BeforeClass method is intended to set up a static shared
154    resource for all methods to use, such as a database connection or in
155    our case a repository of yang model definitions (for example).
156    In this method you can initialize static class variables for later use.
157 #. *A new instance of your test class is instantiated* - A new instance of your
158    test class is not instantiated so each method can have its own sandbox.
159 #. **@Before** - This annotation can appear once in a test class on a public
160    method which takes no arguments.
161    This method is called before EVERY test method.
162    It purpose to to provide a location for common initialization logic that each
163    test method requires, such as instantiating the class under test and
164    performing some generic set up.
165    During this step you can class level variables for use in your test methods.
166    Note, you do NOT have to worry about synchronization with the class level
167    variables initialized here, because each test method has its own copy of the
168    variables.
169    Of course if your tests deals with concurrency, or you are modifying a static
170    resource (not recommended) you may still need to deal with concurrency.
171 #. **@Test** - See above. At this point one of the @Test annotated methods is
172    executed.
173 #. **@After** - The method with this annotation is executed after the
174    @Test annotated method executes. This method is executed regardless
175    of the passing or failing of the JUnit test and provides an
176    opportunity to clean up after your test, such as deleting temporary
177    files or deleting records from a database.
178 #. *At this point the testing framework will loop back to the @Before on
179    a new test class instance to execute the next test method.*
180 #. **@AfterClass** - this annotation placed on a static method is used
181    to clean up the initialization performed in the ``@BeforeClass`` method.
182    It is executed once when all @Test methods have been executed.
183
184 Here is a sample JUnit test class that illustrates the ordering:
185
186 .. code:: java
187
188     package org.opendaylight.controller.sal.restconf.impl.cnsn.to.json.test;
189
190     import org.junit.After;
191     import org.junit.AfterClass;
192     import org.junit.Before;
193     import org.junit.BeforeClass;
194     import org.junit.Test;
195
196     public class Temp {
197
198        @BeforeClass
199        public static void staticInit(){
200            System.out.println( "Static Init" );
201        }
202
203        @Before
204        public void testInit(){
205            System.out.println( "Test Init - " + this );
206        }
207
208        @Test
209        public void testOne(){
210            System.out.println( "Test One - " + this );
211        }
212
213        @Test
214        public void testTwo(){
215            System.out.println( "Test Two - " + this );
216        }
217
218        @After
219        public void testCleanUp(){
220            System.out.println( "Test Clean Up - " + this );
221        }
222
223        @AfterClass
224        public static void staticCleanUp(){
225            System.out.println( "Static Clean Up" );
226        }
227
228    }
229
230 If you execute this through the test framework
231 you would get output similar to this:
232
233
234 .. code::
235
236    Static Init
237    Test Init - org.opendaylight.controller.sal.restconf.impl.cnsn.to.json.test.Temp@7476a6d9
238    Test One - org.opendaylight.controller.sal.restconf.impl.cnsn.to.json.test.Temp@7476a6d9
239    Test Clean Up - org.opendaylight.controller.sal.restconf.impl.cnsn.to.json.test.Temp@7476a6d9
240    Test Init - org.opendaylight.controller.sal.restconf.impl.cnsn.to.json.test.Temp@7260c384
241    Test Two - org.opendaylight.controller.sal.restconf.impl.cnsn.to.json.test.Temp@7260c384
242    Test Clean Up - org.opendaylight.controller.sal.restconf.impl.cnsn.to.json.test.Temp@7260c384
243    Static Clean Up
244
245 Notice that the object address is different for the two initialization calls,
246 indicating that each test method did indeed receive its own object.
247
248 .. note::
249
250    It is important to not rely on the order of execution of the test methods
251    when possible.
252    JUnit can be configured to execute in parallel test methods from different
253    classes but also inside the same class.
254
255    *More details on parallel execution experimental support in Junit5 can be
256    found at this URL:*
257
258    *https://junit.org/junit5/docs/current/user-guide/index.html#writing-tests-parallel-execution*
259
260 Now that you have a shell for your test framework, its important to discuss
261 how you indicate failures or passes in your JUnit tests.
262 For that we need to discuss about assertions.
263
264 Validating Your Tests - Assertions
265 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
266
267 In order to have a complete unit test it is important to have quality
268 assertions in your tests which actually validate that the behavior
269 observed is the behavior that you wanted.
270
271 -  **Passing a JUnit Test** - A JUnit test is considered to have passed
272    if the method executes and returns without throwing an exception.
273 -  **Failing a JUnit Test** - A JUnit test will be considered failed if
274    an exception is thrown from it. There are a number of libraries that
275    have been created to make this easier, most notable the Assert library.
276
277 The Assert library is closely tied to the JUnit library and provides
278 methods to make it easy to validate that the data return is non null,
279 equals another object etc. For example, if you want to assert that two
280 objects are equal, you can use the ``eassertEquals( ... )`` method.
281
282 .. code:: java
283
284    public void test(){
285        Object expectedObj = ...
286        Object actualObj = ...
287        assertEquals( "Error message if not equal", expectedObj, actualObj );
288    }
289
290 This is a very common pattern for the assert methods. You can provide a
291 string which provides a more descriptive error if things are not equal.
292 Additionally, the Assertion framework will also to string the objects
293 for comparison if things don't match to provide further information.
294 Check out the Assert class for all of the other combinations:
295 http://junit.sourceforge.net/javadoc/org/junit/Assert.html
296
297 .. note::
298    It is a good idea to use the most appropriate method for your assertions.
299    For example you can assert equality by simply doing
300    ``assertTrue( expectedObj.equals( actualObj ) )``.
301    However the assert methods will do additional things like null checks,
302    and printing out more detailed information on the error
303    if the assertion does not pass.
304    So in this case, using ``assertEquals`` is better as it would null check and
305    print the values of the expected and actual objects for you automatically,
306    making the act of asserting really easy!.
307
308 Concurrency in Unit test
309 ~~~~~~~~~~~~~~~~~~~~~~~~
310
311 In general, it is easier to avoid having multiple threads in your unit tests
312 for a few reasons:
313
314 #. JUnit will only fail if an exception is thrown in the primary thread
315    which it is executing your test from - exceptions thrown on other
316    threads will not cause the test to fail!
317 #. Tests will slow down when other threads get spawned and you will
318    start competing for system resources.
319 #. You have to deal with all of the other concurrency issues in your
320    test that you do else where (waiting for threads, synchronizing
321    objects etc) which makes the test harder to read.
322
323 If you do find that you need to deal with multiple threads in your test
324 then you will need to take great care to make sure you are handling
325 uncaught exceptions etc. If the class you are testing uses thread pools
326 it is a good idea to refactor your test to pass in a ThreadPool instead
327 of instantiate your own thread pool. If you do that, then you can use
328 one of the following options to avoid multiple threads:
329
330 -  Pass in a thread pool executor that executes the ``runnable`` / ``callable``
331    on the same thread
332 -  Capture the ``runnables`` in a mock executer and then execute the run /
333    call method at a later point.
334
335 [TODO - need to provide more examples for the above two cases]
336
337 Mocking
338 ~~~~~~~
339
340 There are a number of frameworks out there which allow you to mock up
341 objects in your Unit tests to simulate behavior.
342 Most of these frameworks take advantage of good modular OO design
343 (i.e. think interfaces, setters, getters etc).
344 Some example mocking frameworks are:
345
346 -  Mockito - https://github.com/mockito/mockito - **Note: Used in
347    controller in a number of places**
348 -  EasyMock - http://easymock.org/
349
350 Please refer to these sites for more details. If you have questions
351 please reach out the mailing lists with questions - if there is enough
352 interest we will develop more detailed best practices around mocking.