pragmatic java test automation
TRANSCRIPT
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
Source of weather data - REST API
http://api.openweathermap.org/data/2.1/find/name?q=riga
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