1 #############################
2 Build Time Testing with JUnit
3 #############################
10 JUnit is a framework for writing build time tests.
11 See their home page http://junit.org/ for more information.
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.
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.
21 Additionally JUnit integrates nicely with the Eclipse and Idea frameworks
22 to provide launching and debugging unit tests from within the IDE framework.
24 Qualities of a Good Unit Test
25 =============================
27 A good unit test will:
31 - No sleeps or thread blocking if you can avoid it
33 #. Run against the public API's of a class (think interfaces!)
34 #. Test a "single" unit of work
36 - Unit tests generally test an isolated piece of functionality.
37 Integration tests are used to test the interaction between two
39 - You can have multiple tests in a single test class, each testing a
40 different piece of functionality... more on that later.
42 #. Contain assertions which validate the functionality
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
55 To run a JUnit tests via the command line you only need to run:
59 However, that only runs the tests, it doesn't recompile them. In general
64 is the best way as it rebuilds your bundle and then executes any JUnit
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
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
83 Example Implementation
84 ======================
86 Below we provide an example of how you can implement a JUnit test in
92 A few things to keep in mind when creating a JUnit test class:
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
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
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
110 Adding JUnit to your Maven Project
111 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
113 To add the JUnit dependency to your maven project you simply add this
114 dependency into the dependencies section of your pom file.
119 <groupId>junit</groupId>
120 <artifactId>junit</artifactId>
121 <version>4.8.1</version>
126 You can exclude the scope and version tags assuming a parent
127 project has defined the dependency in the dependency management
130 Creating your Test Class - Annotations
131 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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
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
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:
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
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
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.
184 Here is a sample JUnit test class that illustrates the ordering:
188 package org.opendaylight.controller.sal.restconf.impl.cnsn.to.json.test;
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;
199 public static void staticInit(){
200 System.out.println( "Static Init" );
204 public void testInit(){
205 System.out.println( "Test Init - " + this );
209 public void testOne(){
210 System.out.println( "Test One - " + this );
214 public void testTwo(){
215 System.out.println( "Test Two - " + this );
219 public void testCleanUp(){
220 System.out.println( "Test Clean Up - " + this );
224 public static void staticCleanUp(){
225 System.out.println( "Static Clean Up" );
230 If you execute this through the test framework
231 you would get output similar to this:
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
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.
250 It is important to not rely on the order of execution of the test methods
252 JUnit can be configured to execute in parallel test methods from different
253 classes but also inside the same class.
255 *More details on parallel execution experimental support in Junit5 can be
258 *https://junit.org/junit5/docs/current/user-guide/index.html#writing-tests-parallel-execution*
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.
264 Validating Your Tests - Assertions
265 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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.
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.
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.
285 Object expectedObj = ...
286 Object actualObj = ...
287 assertEquals( "Error message if not equal", expectedObj, actualObj );
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
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!.
308 Concurrency in Unit test
309 ~~~~~~~~~~~~~~~~~~~~~~~~
311 In general, it is easier to avoid having multiple threads in your unit tests
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.
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:
330 - Pass in a thread pool executor that executes the ``runnable`` / ``callable``
332 - Capture the ``runnables`` in a mock executer and then execute the run /
333 call method at a later point.
335 [TODO - need to provide more examples for the above two cases]
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:
346 - Mockito - https://github.com/mockito/mockito - **Note: Used in
347 controller in a number of places**
348 - EasyMock - http://easymock.org/
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.