JUnit

TDD: JUnit Introduction

Topics

  • What is JUnit? 
  • JUnit annotations 
    • @Test 
    • @Before, @After 
    • @BeforeClass, @AfterClass 
  • Assert statements 
  • AssertThat 
  • Testing tools 
  • Exception handling 
  • Parameterization
  • Best practices

What is JUnit?

  • Unit testing framework for Java 
  • De-facto standard for unit testing 
  • Free and open-sourced

JUnit Annotations @Test @Before, @After @BeforeClass, @AfterClass @Ignore

How to write JUnit test?

  • Create test class with test methods 
  • Each test method has method signature 
    • Annotate it with @Test 
    • public 
    • void return type 
    • No arguments 
  • Add fixtures 
    • @Before and @After to run before/after each test method 
    • @BeforeClass and @AfterClass to run once before/after all test methods 
    • @Ignore to temporarily ignore the testing

Example Test class

 

public class CalculatorTest {
 private Calculator calculator;
 @Before
 public void setup() {
 calculator = new Calculator();
 }
 @Test public void
 should_return_added_value_when_two_numbers_are_given() {
 assertEquals(5, calculator.add(2, 3));
 assertThat(calculator.add(2, 3), equalTo(5));
 }
 @Test public void
 should_return_subtraction_when_two_numbers_are_given() {
 assertEquals(-1, calculator.subtract(2, 3));
 assertThat(calculator.subtract(2, 3), equalTo(-1));
 }
}

Assert Statements

  • JUnit Assertions are methods starting with assert 
  • Determines the success or failure of a test
  • An assert is simply a comparison between an expected value and an actual value 
    • Two variants > assertXXX(...) 
    • assertXXX(String message, ...) - the message is displayed when the assertXXX() fails
  • Asserts expected.equals(actual) behavior 
    • assertEquals(expected, actual) 
    • assertEquals(String message, expected, actual) 
  • Asserts expected == actual behavior 
    • assertSame(Object expected, Object actual) 
    • assertSame(String message, Object expected, Object actual) 
  • Asserts that a condition is true 
    • assertTrue(boolean condition) 
    • assertTrue(String message, boolean condition) 
  • Asserts that a condition is false 
    • assertFalse(boolean condition) 
    • assertFalse(String message, boolean condition)
  • Asserts object reference is null 
    • assertNull(Object obj) 
    • assertNull(String message, Object obj) 
  • Asserts object reference is not null 
    • assertNotNull(Object obj) 
    • assertNotNull(String message, Object obj) 
  • Forces a failure 
    • fail() 
    • fail(String message)

Hamcrest AssertThat

What is Hamcrest? 

  • Hamcrest is a framework for writing matcher objects, allowing ‘match’ rules to be defined declaratively 
  • These matchers are used extensively in JUnit 
  • JUnit 4.4 introduced a new assert “assertThat” using 
    • org.hamcrest.CoreMatchers 
    • org.junit.matchers.JUnitMatchers
  • Usage: assertThat([value], [matcher statement]);

Example: Hamcrest assertThat

@Test
 public void testDriverOne(){
 assertThat(driver.getAge(), is(18)); // is(..) is deprecated
 assertThat(driver.getAge(), equalTo(18)); // use equalTo(..) instead
 assertThat(driver.getAge(), not(17));
 assertThat(driver.getName(), equalTo(“Sang Shin”));
 assertThat(driver.getName(), containsString(“Sang Shin”));
 assertThat(driver.getFirstName(),
 either(containsString(“mun”)).or(containsString(‘abc’)));
}

Why Hamcrest? 

  • More read'able and type'able 
    • This syntax allows you to think in terms of subject, verb, object (assert “x is 3”) rather than assertEquals which uses verb, object, subject(assert “equals 3 x”) 
  • Combinations 
    • Any matcher statements can be negated (not(s)) 
    • Any matcher statements can be combined (either(s) or (t))

Eclipse: Java->Editor>Content-Assist->Favorites 

Eclipse IDE cannot always create the corresponding static import statements automatically. 

You can configure the Eclipse IDE to use code completion to insert typical JUnit method calls and to add the static import automatically. For this open the Preferences via Window ▸ Preferences and select Java Editor Content Assist ▸ ▸ ▸ Favorites-> New Type

  • org.junit.Assert 
  • org.hamcrest.CoreMatchers 
  • org.hamcrest.Matchers

Eclipse: Java->Editor>Content-Assist->Favorites

 Favorites

Lab: Exercise 1: JUnit Annotations 1651_tdd_junit.zip

Testing Tools

  • Automatic testing tools 
    • Each time a change is made on the source code, tests are run 
    • Infinitest 
  • Code coverage tools 
    • Used to describe the degree to which the source code of a program is executed when a particular test suite runs 
    • EclEmma, JaCoco 
  • Source code version control 
    • Git 
  • Continuous Build tools 
    • Jenkins

Lab: Exercise 2: Installation of Tools 1651_tdd_junit.zip

Exception Handling

Three schemes of handling exceptions in JUnit

  • @Test(expected = <Exception.class> ) 
  • @Rule 
  • try-catch idiom

@Test(expected =<Exception.class> )

Supported in JUnit 4

@Test (expected = IllegalArgumentException.class) 
public void throwsExceptionWhenNegativeNumbersAreGiven() { 
calculator.add("-1,3"); // This throws an IllegalArgumentException
 }

@Rule 

  • Supported in JUnit 4 
  • The rule must be a public field marked with @Rule annotation
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void throwsExceptionWhenNegativeNumbersAreGiven() {
 // arrange
 thrown.expect(IllegalArgumentException.class);
 thrown.expectMessage("negatives not allowed: -1 4”);
 // act
 calculator.add("-1,4");
}

 try-catch 

  • Supported in JUnit 3 and JUnit 4 
  • The test will fail when no exception is thrown and the exception itself is verified in a catch clause 
  • Least favored option

 

@Test
public void throwsExceptionWhenNegativeNumbersAreGiven() {
 try {
 calculator.add("-1,4");
 fail("Should throw an exception if one of given numbers is negative");
 } catch (Exception e) {
 assertThat(e)
 .isInstanceOf(IllegalArgumentException.class)
 .hasMessage("negatives not allowed: -1 4");
 }
}

Lab: Exercise 3: Exception Handling 1651_tdd_junit.zip

Parameterization

Parameterized Testing 

  • The Parameterized Test is used when we find ourselves writing identical tests where only a few data input values are different but the logic is the same 
  • Only one test method is needed which will have parameterized data supplied to it

Example: Parameterized testing

@RunWith(Parameterized.class)
public class CalculatorTest {
 private Calculator calculator;
 private int x;
 private int y;
 private int result;
 public CalculatorTest(int x, int y, int result) {
 this.x = x;
 this.y = y;
 this.result = result;
 }
 @Parameters
 public static Collection testValues() {
 return Arrays.asList(new Object[][] {
 { 2, 3, 5 },
 { 4, 9, 13 },
 { 1, 9, 10 },
 });
}

Lab: Exercise 4: Parameterization 1651_tdd_junit.zip

JUnit Best Practices

Test Code vs Production Code

  • Your test code becomes part of the codebase 
  • It is backed up and put into a source code repository along with the production code
  • Test code needs to be documented, although not as heavily as the production code 
  • Note that test code will most likely not deploy with the production code

Be thorough 

  • Write tests for everything 
    • Except methods that are "too simple to fail" 
    • Only trivial getter/setter methods are too simple to fail 
  • Write multiple tests for each method 
    • "positive" testing 
    • "negative" testing 
    • boundary value testing (BVT)

Download Course Content