TESTING JAVA
CODE
EFFECTIVELY
ANDRES ALMIRAY
@AALMIRAY
DISCLAIMER
GET THE CODE
https://github.com/aalmiray/javatrove/
ASSERTIONS
Hamcrest - http://hamcrest.org/JavaHamcrest/
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
public class SampleServiceTest {
public void sayHello() {
// given:
SampleService service = new SampleService();
// expect:
assertThat(service.sayHello("Test"), equalTo("Hello Test"));
}
}	
  
Hamcrest - http://hamcrest.org/JavaHamcrest/
•  Descriptive conditions
•  Easily extensible
•  Bundled with JUnit
AssertJ-
http://joel-costigliola.github.io/assertj/
import static org.assertj.core.api.Assertions.assertThat;
public class SampleServiceTest {
public void sayHello() {
// given:
SampleService service = new SampleService();
// expect:
assertThat(service.sayHello("Test")).isEqualTo("Hello Test");
}
}	
  
AssertJ-
http://joel-costigliola.github.io/assertj/
•  Fluent interface design for assertions
•  Inspired by FEST-assert and Hamcrest
Truth- http://google.github.io/truth/
import static com.google.common.truth.Truth.assertThat.assertThat;
public class SampleServiceTest {
public void sayHello() {
// given:
SampleService service = new SampleService();
// expect:
assertThat(service.sayHello("Test")).isEqualTo("Hello Test");
}
}	
  
Truth- http://google.github.io/truth/
•  Fluent interface design for assertions/propositions
•  Inspired by FEST-assert and Hamcrest
•  Curated by Google
JGoTesting-
https://gitlab.com/tastapod/jgotesting
public class MyTest {
@Rule
public final JGoTestRule test = new JGoTestRule();
@Test
public void checksSeveralThings() {
test.log("This message only appears if we fail");
// All these are checked, then they all report as failures
test
.check("this fails", "one", equalTo("ONE")) // Hamcrest matcher
.check("this also fails", "two", equalTo("TWO"))
.check("so does this", "one".equals("ONE")) // boolean check
.check("and this", "two".equals("TWO"));
// Fails with four errors. Sweet!
}
}
JGoTesting-
https://gitlab.com/tastapod/jgotesting
•  Inspired in Go’s testing support.
•  Multiple checks may result in a single test failure.
GENERAL
NETWORK AWARE JAVAFX APP
Write an application that consumes a REST
API.
Components must be small and reusable.
Say no to boilerplate code.
Behavior should be easy to test.
GITHUB API
Well documented REST API
Latest version located at
https://developer.github.com/v3/
We’re interested in the repositories
operation for now
QUERYING REPOSITORIES
API described at
https://developer.github.com/v3/repos/#list-
organization-repositories
Given a query of the form
GET /orgs/${organization}/repos
QUERY RESULT
[
{
"id": 1296269,
"owner": { /* omitted for brevity */ },
"name": "Hello-World",
"full_name": "octocat/Hello-World",
"description": "This your first repo!",
"html_url": "https://github.com/octocat/Hello-World",
/* many other properties follow */
},
/* additional repositories if they exist */
]
WHAT WE’LL NEED
Dependency Injection
HTTP client & REST behavior
JSON mapping
Boilerplate buster
Handle concurrency
JUnitParams -
https://github.com/Pragmatists/JUnitParams
@RunWith(JUnitParamsRunner.class)
public class SampleServiceTest {
@Test
@Parameters({",Howdy stranger!",
"Test, Hello Test"})
public void sayHello(String input, String output) {
// given:
SampleService service = new SampleService();
// expect:
assertThat(service.sayHello(input), equalTo(output));
}
}	
  
JUnitParams -
https://github.com/Pragmatists/JUnitParams
•  Parameterize multiple methods with different argument
cardinality.
•  Different data provider strategies.
Mockito - http://mockito.org
@Test @Parameters({",Howdy stranger!", "Test, Hello Test"})
public void sayHelloAction(String input, String output) {
// given:
SampleController controller = new SampleController();
controller.setModel(new SampleModel());
controller.setService(mock(SampleService.class));
// expectations
when(controller.getService().sayHello(input)).thenReturn(output);
// when:
controller.getModel().setInput(input);
controller.sayHello();
// then:
assertThat(controller.getModel().getOutput(), equalTo(output));
verify(controller.getService(), only()).sayHello(input);
}	
  
Mockito - http://mockito.org
•  Fluid DSL based on static methods.
•  Provides support for Stubs, Mocks, and Spies.
•  Mock interfaces, abstract classes, and concrete classes.
Jukito - https://github.com/ArcBees/Jukito
@RunWith(JukitoRunner.class)
public class SampleControllerJukitoTest {
@Inject private SampleController controller;
@Before
public void setupMocks(SampleService sampleService) {
when(sampleService.sayHello("Test")).thenReturn("Hello Test");
}
@Test
public void sayHelloAction() {
controller.setModel(new SampleModel());
controller.getModel().setInput("Test");
controller.sayHello();
assertThat(controller.getModel().getOutput(),
equalTo("Hello Test"));
verify(controller.getService(), only()).sayHello("Test");
}
}	
  
Jukito - https://github.com/ArcBees/Jukito
•  Combines JUnit, Guice, and Mockito
•  Bind multiple values to the same source type.
•  Can be used to parameterize test methods.
Spock- http://spockframework.org
@spock.lang.Unroll
class SampleControllerSpec extends spock.lang.Specification {
def "Invoke say hello with #input results in #output"() {
given:
SampleController controller = new SampleController()
controller.model = new SampleModel()
controller.service = Mock(SampleService) {
sayHello(input) >> output }
when:
controller.model.input = input
controller.sayHello()
then:
controller.model.output == output
where:
input << ['', 'Test']
output << ['Howdy, stranger!', 'Hello Test']
}
}	
  
Spock- http://spockframework.org
@spock.lang.Unroll
class SampleControllerSpec extends spock.lang.Specification {
def "Invoke say hello with #input results in #output"() {
given:
SampleController controller = new SampleController()
controller.model = new SampleModel()
controller.service = Mock(SampleService) {
sayHello(input) >> output }
when:
controller.model.input = input
controller.sayHello()
then:
controller.model.output == output
where:
input | output
'' | 'Test'
'Howdy, stranger!' | 'Hello Test'
}
}	
  
Spock- http://spockframework.org
•  Groovy based DSL.
•  Parameterize multiple methods with different argument
cardinality.
•  Parameterize test method names.
•  JUnit friendly (can use extensions and rules).
Awaitility -
https://github.com/awaitility/awaitility
@Test
public void happyPath(Github github) {
// given:
Collection<Repository> repositories = createSampleRepositories();
when(github.repositories(ORGANIZATION))
.thenReturn(Observable.from(repositories));
// when:
model.setOrganization(ORGANIZATION);
controller.load();
await().timeout(2, SECONDS).until(model::getState, equalTo(State.READY));
// then:
assertThat(model.getRepositories(), hasSize(10));
assertThat(model.getRepositories(), equalTo(repositories));
verify(github, only()).repositories(ORGANIZATION);
}	
  
Awaitility -
https://github.com/awaitility/awaitility
•  DSL for testing multi-threaded code.
•  Extensions available for Java8, Groovy, and Scala.
•  Conditions can be customized with Hamcrest matchers.
WireMock- http://wiremock.org/
import static com.github.tomakehurst.wiremock.client.WireMock.*;
String nextUrl = "/organizations/1/repos?page=2";
List<Repository> repositories = createSampleRepositories();
stubFor(get(urlEqualTo("/orgs/" + ORGANIZATION + "/repos"))
.willReturn(aResponse()
.withStatus(200)
.withHeader("Content-Type", "text/json")
.withHeader("Link", "<http://localhost:8080" + nextUrl + ">; rel="next"")
.withBody(repositoriesAsJSON(repositories.subList(0, 5), objectMapper))));
stubFor(get(urlEqualTo(nextUrl ))
.willReturn(aResponse()
.withStatus(200)
.withHeader("Content-Type", "text/json")
.withBody(repositoriesAsJSON(repositories.subList(5, 10), objectMapper))));	
  
WireMock- http://wiremock.org/
•  Supply custom HTTP response payloads.
•  DSL for matching HTTP requests.
•  Supports record and playback.
WEB
TRIVIAL TODO WEBAPP
Store todo items in a database
Expose operations via REST API
WHAT WE’LL NEED
Dependency Injection
JSON mapping
Boilerplate buster
Handle persistence
REST-assured -
https://github.com/rest-assured/rest-assured
import static io.restassured.RestAssured.given;
import static java.util.Arrays.asList;
import static org.hamcrest.Matchers.equalTo;
@Test
public void _01_initial_data_is_loaded() {
given().port(4567).
when().
get("/todos").
then().
body("todos.description", equalTo(asList("Add Javadoc")));
}	
  
REST-assured -
https://github.com/rest-assured/rest-assured
•  DSL for issuing HTTP requests
•  Validate and navigate response body if JSON, XML, or HTML
Arquillian- http://arquillian.org
@Deployment
public static WebArchive createDeployment() throws Exception {
File rootDir = new File(System.getProperty("user.dir"));
File[] files = Maven.resolver()
.resolve(…).withTransitivity().asFile();
return ShrinkWrap.create(WebArchive.class, "application.war")
.addPackage(”com.acme”)
.setWebXML(new File(rootDir, "src/main/webapp/WEB-INF/web.xml"))
.addAsLibraries(files);
}	
  
Arquillian- http://arquillian.org
•  Container based testing, supporting Jetty, Tomcat, Glassfish,
Wildfly and others.
•  Create deployable archives with Shrinkwrap.
•  Combine with REST-assured for better results.
MISC
PdfUnit- http://www.pdfunit.com
@Test
public void hasText_OnFirstPage_InRegion() throws Exception {
String pdfUnderTest = "documentUnderTest.pdf";
int leftX = 17; // in millimeter
int upperY = 45;
int width = 80;
int height = 50;
PageRegion addressRegion = new PageRegion(leftX, upperY, width, height);
AssertThat.document(pdfUnderTest)
.restrictedTo(FIRST_PAGE)
.restrictedTo(addressRegion)
.hasText()
.containing("John Doe Ltd.");
}	
  
XMLUnit- http://www.xmlunit.org
import org.custommonkey.xmlunit.XMLTestCase;
public class TestXmlContainingTypeAttribute extends XMLTestCase {
public void testXmlWithTypeAttribute() throws Exception {
String xml = "<data type="someType">" +
"<nested type="some_other_type">value</nested></data>";
XMLSerializer tested = new XMLSerializer();
tested.setTypeHintsEnabled(false);
tested.setTypeHintsCompatibility(false);
tested.setRootName("data");
JSON jsonRepresentation = tested.read(xml);
String result = tested.write(jsonRepresentation);
assertXMLEqual(xml, result);
}
}	
  
THANK YOU!
ANDRES ALMIRAY
@AALMIRAY

Testing Java Code Effectively