Pragmatic Java Test Automation

Preview:

Citation preview

Java Test AutomationReal-world patterns and practices

Dmitry Buzdin

TESTING AUTOMATION

Wat iz test automation?

Tests are automated!

Tests could be run on developer laptop

Tests are running in CI on regular basis

Tests do not require network access

Signs that there is not enough automation

Starting GUI to check backend changes

Deploying to server to check functionality

Relying on debug logging

Testing is for testers

You do not sleep well

Testing patterns in this presentation are applicable to any framework/system

SAMPLE APPLICATION

User Interface

Application Services

Domain Model

Integration Components

External Services & Storage

Typical Layers

Our Requirements

Display weather forecasts

Store them in database

Lots of other usual requirements

Cloud, HTML5, BigData...

Weather REST APISQL DB

Integration Layer

Other APIs

ORM

Domain Model

Service Layer

REST API

Web Client

Technology Stack

Front-end - Twitter Bootstrap + jQuery

REST - JAX-RS 1.1 / Jersey

Dependency Injection - CDI / Weld

ORM - JPA 2.0 / Hibernate

SQL DB - PostgreSQL

DEMO

TESTING STRATEGY

Unit Tests

Integration Tests

Functional Tests

UNIT TESTING

Unit Tests

Classes are tested in isolation (almost)

One test method checks one use-case

One class <-> one test class

Weather REST APISQL DB

Integration Layer

Other APIs

ORM

Domain Model

Service Layer

REST API

Web Client

JUnit Tests

http://junit.org/

@Beforepublic void setUp() { // Preparing object for test}

@Testpublic void shouldFindWeatherByCity() throws Exception {

// Conditions set-up// Method under test invocation// Assertions

}

Use Dependency Injection

Separation of classes

Mostly about testing

Popular DI frameworks

Spring

CDI

Guice

Injection Types

by constructor

by setter

by field

Mockito Mocks

http://code.google.com/p/mockito/

// Mocking all class dependenciesservice = new WeatherServiceImpl();service.weatherSource = Mockito.mock(WeatherSource.class);

// Sets-up mock reactionwhen(service.weatherSource.findByCityName(eq("Kolka"))).thenReturn(expectedResult);

// Your method under test here

// Verifies interactions with mockverify(service.entityManager).persist(any(Temperature.class));

Hamcrest Matchers

assertThat(ages, everyItem(greaterThan(18)));

assertThat(param, equalTo(42));

assertThat(param, notNullValue());

assertThat(object, is(String.class))

assertThat(object, anyOf(is(String.class), is(Integer.class))

http://code.google.com/p/hamcrest/

Benefits

Forget assertEquals() !

Hamcrest matchers are

expressive

flexible

extendable

DEMO

INTEGRATION TESTING

Integration Tests

Should not start the whole application

Testing integration components

Remote API calls

Data conversion

Fault-scenarios

Weather REST APISQL DB

Integration Layer

Other APIs

ORM

Domain Model

Service Layer

REST API

Web Client

Fake Dependencies

Write code for emulating dependencies

Fake Web Service

Fake FTP server

Fake InputStream

Fake XML response

DEMO

Persistence Tests

Isolate and test all persistence operations

Ideally all CRUD operations

Could be done in Generic way

In-memory Storage

Transient database for test execution

Some DBs have it built-in

For SQL DB mocking pick H2

Fast

Emulation modes

http://www.h2database.com/

DEMO

FUNCTIONAL TESTING

Functional Tests

Not testing UI

Starting application context

Emulating multiple user requests

Persisting intermediate results

Weather REST APISQL DB

Integration Layer

Other APIs

ORM

Domain Model

Service Layer

REST API

Web Client

Embedded Container

Test should start application

It is possible to start embedded

CDI Container

EJB Container

Spring Container

Functional Testing using Service Layer

Ignoring GUI data conversion

Easier to test

Faster test execution

Mock Integrations

Could be replaced using

Properties and factory beans

Spring @Profile

CDI @Alternative

Guice Modules

Environment Switch

Application should run in several modes

Done with System environment variable

Typical modes:

production

local deployment

embedded testing

Configuration Override

Environments overrides settings

Hierarchical configurations

Properties, YAML or other

Initial Data

Reset database after every test and insert initial data

Reuse ORM mapping or other persistence layer

Or use specialized tools like DbUnit

API-Level Testing

Write test for your API

Some examples:

SOAP

REST

EJB

DEMO

Weather REST APISQL DB

Integration Layer

Other APIs

ORM

Domain Model

Service Layer

REST API

Web Client

Embedded Web Server

It is possible to run embedded

Jetty

Glassfish/Grizzly

JUnit Rules

@Rulepublic EmbeddedJetty jetty = new EmbeddedJetty();

@Testpublic void shouldTestEmbeddedJetty() { ...}

DEMO

SUMMARY

Why is it all needed?

Decrease cost of change

Increase software quality

Remove fear of making changes

When Testing is Enough?

If CI build passes it is safe to deploy to

production

What was not covered?

Automated

Acceptance testing

GUI-level testing

Performance testing

Dmitry Buzdin

Freelance Software Architect

http://buzdin.lvbuzdin@gmail.com

@buzdin

Recommended