0% found this document useful (0 votes)
42 views

Unit Testing Using Junit: Inf5750/9750 - Lecture 4 (Part Ii)

Unit testing allows developers to test components of code in isolation to identify where bugs are located. The JUnit framework is commonly used for unit testing in Java. It allows developers to write test methods annotated with @Test and use assertions to verify expected outcomes. Fixtures can be set up using @Before and @After annotations to provide common resources for tests. The Assert class contains methods like assertEquals to validate test conditions and assert failures if tests do not pass.

Uploaded by

darwinvargas2011
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
42 views

Unit Testing Using Junit: Inf5750/9750 - Lecture 4 (Part Ii)

Unit testing allows developers to test components of code in isolation to identify where bugs are located. The JUnit framework is commonly used for unit testing in Java. It allows developers to write test methods annotated with @Test and use assertions to verify expected outcomes. Fixtures can be set up using @Before and @After annotations to provide common resources for tests. The Assert class contains methods like assertEquals to validate test conditions and assert failures if tests do not pass.

Uploaded by

darwinvargas2011
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 29

Unit Testing

using JUnit
INF5750/9750 - Lecture 4 (Part II)
Problem area
● Code components must be tested!
○ Confirms that your code works
● Components must be tested in isolation
○ A functional test can tell you that a bug exists in the
implementation
○ A unit test tells you where the bug is located

Test failure!
Component A But where
is the bug?
<using> <using>

Component B Component C
Example: The Calculator
public interface Calculator
{
int add( int number1, int number2 );

int multiply( int number1, int number2 );


}

public class DefaultCalculator


implements Calculator
{
public int add( int number1, int number2 )
{
return number1 + number2;
}

public int multiply( int number1, int number2 )


{
return number1 * number2;
}
}
Approaches to unit testing
● Write a small command-line program, enter values, and
verify output
○ Involves your ability to type numbers
○ Requires skills in mental calculation
○ Doesn’t verify your code when its released
Approaches to unit testing
● Write a simple test program
○ Objective and preserves testing efforts
○ Requires you to monitor the screen for error messages
○ Inflexible when more tests are needed
public class TestCalculator
{
public static void main( String[] args )
{
Calculator calculator = new DefaultCalculator();

int result = calculator.add( 8, 7 );

if ( result != 15 )
{
System.out.println( ”Wrong result: ” + result );
}
}
}
The preferred solution
● Use a unit testing framework like JUnit
○ A unit is the smallest testable component in an
application
○ A unit is in most cases a method
○ A unit does not depend on other components which
are not unit tested themselves
○ Focus on whether a method is following its API
contract

Component A Unit test A

<using> <using>

Unit test B Component B Component C Unit test C


JUnit
● De facto standard for developing unit tests in Java
○ One of the most important Java libraries ever developed
○ Made unit testing easy and popular among developers
○ Driven by annotations
○ Spring provides integration with JUnit
Using JUnit annotations
● No need to follow naming conventions
○ Tests identified by @Test annotation
○ Fixture methods identified by @Before and @After
annotations

● Class-scoped fixture
○ Identified by @BeforeClass and @AfterClass annotations
○ Useful for setting up expensive resources, but be careful…

● Ignored tests
○ Identified by @Ignore annotation
○ Useful for slow tests and tests failing for reasons beyond you

● Timed tests
○ Identified by providing a parameter @Test(timeout=500)
○ Useful for benchmarking, network, deadlock testing
Test fixtures
● Tests may require common resources to be set up
○ Complex data structures
○ Database connections

● A fixture is a set of common needed resources


○ A fixture can be created by overriding the setUp and
tearDown methods from TestCase
○ setUp is invoked before each test, tearDown after

TestCase
lifecycle
setUp() testXXX() tearDown()
JUnit Calculator test
import static junit.framework.Assert.*;
Static import of Assert
public class CalculatorTest
{
Calculator calculator;

Fixture
@Before
public void before()
{
Fixture calculator = new DefaultCalculator();
}

@Test
public void addTest()
{
Use assertEquals to
int sum = calculator.add( 8, 7 );
verify output assertEquals( sum, 15 );
}

@Test
public void multiplyTest()
{
}
}
Example: The EventDAO
public class Event()
Event object {
private int id;
private String title;
private Date date;

// constructors
// get and set methods
}

public interface EventDAO


EventDAO interface {
int saveEvent( Event event );

Event getEvent( int id );

void deleteEvent( Event event );


}
EventDAOTest
import static junit.framework.Assert.assertEquals;
Assert imported statically
@Before
public void init()
Fixture method identified {
by the @Before annotation eventDAO = new MemoryEventDAO();
event = new Event( ”U2 concert”, date );
}

@Test
public void saveEvent()
Test identified by the @Test {
int id = eventDAO.saveEvent( event );
annotation. Test signature is
equal to method signature.
event = eventDAO.getEvent( id );

assertEquals( id, event.getId() );


}

Test being ignored @Test @Ignore


Public void getEvent()
{
// Testing code...
}
The Assert class
● Contains methods for testing whether:
○ Conditions are true or false
○ Objects are equal or not
○ Objects are null or not

● If the test fails, an AssertionFailedError is thrown


● All methods have overloads for various parameter types
● Methods available because TestCase inherits Assert
Assert
<inherits>

TestCase
<inherits>

EventDAOTest
Assert methods
Method Description

assertTrue( boolean ) Asserts that a condition is true.

assertFalse( boolean ) Asserts that a condition is false.

assertEquals( Object, Object ) Asserts that two objects are equal.

assertArrayEquals ( Object[], Object[] ) Asserts that all elements in the two arrays are equal

assertNotNull( Object ) Asserts that an object is not null.

assertNull( Object ) Asserts that an object is null.

assertSame( Object, Object ) Asserts that two references refer to the same object.

assertNotSame( Object, Object ) Asserts that two references do not refer to the same object.

fail( String ) Asserts that a test fails, and prints the given message.
Assert in EventDAOTest

@Test
public void testSaveEvent()
{
Asserts that the saved object is int id = eventDAO.saveEvent( event );
event = eventDAO.getEvent( id );
equal to the retrieved object
assertEquals( id, event.getId() );
assertEquals( ”U2 concert”, event.getTitle() );
}

Saves and retrieves an Event


with the generated identifier @Test
public void testGetEvent()
{
int id = eventDAO.saveEvent( event );
event = eventDAO.getEvent( id );
An object is expected assertNotNull( event );
event = eventDAO.getEvent( -1 );
assertNull( event );
}
Asserts that null is returned
when no object exists
Core Hamcrest Matchers - assertThat
Examples The matchers

allOf(...) - same as && (AND)


assertThat("good", allOf(equalTo("good"), startsWith("good"))); equalTo(...) - object equivalence,
startsWith(...) - string matching

assertThat("good", not(allOf(equalTo("bad"), equalTo("good")))); not(...) - same as != (NOT EQUAL)

assertThat("good", anyOf(equalTo("bad"), equalTo("good"))); anyOf (...) - same as || (OR)

assertThat(theBiscuit, equalTo(myBiscuit));
assertThat(theBiscuit, is(equalTo(myBiscuit))); is - syntactic sugar - all 3 statements are same
assertThat(theBiscuit, is(myBiscuit));

● Don’t use too much sugar!! - Only use for readability


Testing Exceptions
● Methods may be required to throw exceptions
● Expected exception can be declared as an annotation
○ @Test( expected = UnsupportedOperationException.class )

Annotation declares that an @Test( expected = UnsupportedOperationException.class )


exception of class public void divideByZero()
UnsupportedOperationException {
is supposed to be thrown calculator.divide( 4, 0 );
}
Running JUnit
● Textual test runner
○ Used from the command line
○ Easy to run

● Integrated with Eclipse


○ Convenient, integrated testing within your development
environment!

● Integrated with Maven


○ Gets included in the build lifecycle!
JUnit with Eclipse
● Eclipse features a JUnit view
● Provides an informative GUI displaying test summaries
● Lets you edit the code, compile and test without leaving
the Eclipse environment
JUnit with Maven
● Maven provides support for automated unit testing with
JUnit
● Unit testing is included in the build lifecycle
○ Verifies that existing components work when other components
are added or changed

<dependency>
<groupId>junit</groupId>
Add dependency <artifactId>junit</artifactId>
to POM to put <version>4.11</version>
JUnit on the classpath <scope>test</scope>
</dependency>

Execute the Maven


$ mvn test
test phase
JUnit with Maven
● Maven requires all test-class names to contain Test
● Standard directory for test classes is src/test/java
● The test phase is mapped to the Surefire plugin
● Surefire will generate reports based on your test runs
● Reports are located in target/surefire-reports
Spring test support
● Spring has excellent test support providing:
○ IoC container caching
○ Dependency injection of test fixture instances / dependencies
○ Transaction management and rollback

● Spring (spring-test) integrates nicely with JUnit

1) Defines underlying test @RunWith(SpringJUnit4ClassRunner.class)


framework //@ContextConfiguration //this will look for a file EventDaoTest-context.xml
@ContextConfiguration(locations={"classpath*:/META-INF/beans.xml"})
@Transactional
2) Defines location of Spring
public class EventDaoTest
config file {
@Autowired
3) Makes class for Private EventDao eventDao;
transactional testing
@Test
public void testSaveEvent( Event event )
{
Autowires dependencies }
}
Unit Testing Spring MVC Controllers
● To test your Spring MVC Controllers, use
ModelAndViewAssert combined with
MockHttpServletRequest, MockHttpSession, and so on from
the org.springframework.mock.web package
1. Instantiate
Controller and
inject mock/stub
Controller
dependencies

Server-side Client-side

2. Execute with the 3. Create client with


WebApplicationContext RESTTemplate and see
and ResponseBody actual data
Spring MVC - Server-side
● Due to autowiring, find the correct @WebAppConfiguration
● MockMvc class provides testing methods for method,
headers, request, response etc.
● standaloneSetup will create WebApplicationContext with
default Spring configuration for a webapp
With full Web Application Spring Configuration With controller-specific setup (more unit-like)
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration("my-servlet-context.xml")
public class MyWebTests { public class MyWebTests {

@Autowired private MockMvc mockMvc;


private WebApplicationContext wac;
@Before
private MockMvc mockMvc; public void setup() {
this.mockMvc = MockMvcBuilders.standaloneSetup(
@Before new AccountController()).build();
public void setup() { }
this.mockMvc = // ...
MockMvcBuilders.webAppContextSetup(this.wac).build(); }
}
// ...
}
MockMvc usage
● perform() - does requests
@Test
public void testReadId() throws Exception {
this.mockMvc.perform(get("/read/1")
.accept(MediaType.parseMediaType("text/html;charset=UTF-8")))
.andExpect(status().isOk())
.andExpect(content().contentType("text/html"))
.andExpect(message.value("Message number 1 was hello"));
}

● model() - access the returned model


● status() - for HTTP Status
● accept() - accept mime type
● For repeated actions, in standalone setup you can:

standaloneSetup(new BaseController()) {
.alwaysExpect(status().isOk())
.alwaysExpect(content().contentType("application/json;charset=UTF-8"))
.build()
}
Best practices
● One unit test for each tested method
○ Makes debugging easier
○ Easier to maintain
● Choose descriptive test method names
○ TestCase: Use the testXXX naming convention
○ Annotations: Use the method signature of the tested method
● Automate your test execution
○ If you add or change features, the old ones must still work
○ Also called regression testing
● Test more than the ”happy path”
○ Out-of-domain values
○ Boundary conditions
Advantages of unit testing
● Improves debugging
○ Easy to track down bugs
● Facilitates refactoring
○ Verifies that existing features still work while changing the code
structure
● Enables teamwork
○ Lets you deliver tested components without waiting for the
whole application to finish
● Promotes object oriented design
○ Requires your code to be divided in small, re-usable units
● Serving as developer documentation
○ Unit tests are samples that demonstrates usage of the API
Mocking Tests...

● We deliberately skip mocking in this course


● And integration tests
● Results in faster testing of the whole
system

● Not because we think its not useful, but


limitation of time
Resources

● Vincent Massol: JUnit in Action


○ Two free sample chapters
○ http://www.manning.com/massol

● JUnit home page (www.junit.org)


○ Articles and forum

● Spring documentation chapter 11


○ http://docs.spring.io/spring/docs/3.2.x/spring-
framework-reference/html/testing.html

You might also like