testing with spring: an introduction

Post on 20-Aug-2015

642 Views

Category:

Software

2 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Testing with Spring: An Introduction Sam Brannen @sam_brannen

Spring eXchange | London, England | November 6, 2014

eXchange 2014

2

Sam Brannen

•  Spring and Java Consultant @ Swiftmind •  Java Developer for over 15 years

•  Spring Framework Core Committer since 2007 –  Component lead for spring-test

•  Spring Trainer •  Speaker on Spring, Java, and testing

•  Swiss Spring User Group Lead

3

Swiftmind

Experts in Spring and Enterprise Java Areas of expertise •  Spring * •  Java EE •  Software Architecture •  Software Engineering Best Practices

Where you find us •  Zurich, Switzerland •  @swiftmind •  http://www.swiftmind.com

4

A Show of Hands…

? ? ?

?

5

Agenda

•  Unit testing

•  Integration testing

•  Context management and DI

•  Transactions and SQL scripts

•  Spring MVC and REST

•  Q&A

6

Unit Testing

7

Unit Tests

•  are simple to set up

•  use dynamic mocks or stubs for dependencies

•  instantiate the SUT, execute the code, and assert expectations

•  run fast

•  but only test a single unit

8

Spring and Unit Testing

•  POJO-based programming model –  Program to interfaces –  IoC / Dependency Injection –  Out-of-container testability –  Third-party mocking frameworks (Mockito, …)

•  Spring testing mocks/stubs –  Servlet –  Portlet –  JNDI –  Spring Environment

9

EventService API

public interface EventService {

List<Event> findAll();

Event save(Event event);

void delete(Event event);}

10

EventService Implementation (1/2)

@Service@Transactionalpublic class StandardEventService implements EventService {

private final EventRepository repository;

@Autowired public StandardEventService(EventRepository repository) { this.repository = repository; }

// ...

11

EventService Implementation (2/2)

public Event save(final Event event) {

// additional business logic ...

return repository.save(event);}

12

EventService Unit Test (1/2)

public class StandardEventServiceTests {

private StandardEventService service; private EventRepository repository;

@Before public void setUp() { repository = mock(EventRepository.class); service = new StandardEventService(repository); }

13

EventService Unit Test (2/2)

@Testpublic void save() { Event event = new Event(); event.setName("test event"); event.setDescription("testing");

given(repository.save(any(Event.class))) .willReturn(event);

Event savedEvent = service.save(event); assertThat(savedEvent, is(equalTo(event)));}

14

Integration Testing

15

Integration Tests

•  test interactions between multiple components

•  relatively easy to set up… •  without external system dependencies

•  challenging to set up… •  with external system dependencies

•  more challenging… •  if application code depends on the container

16

Integration Test Complexity

Complexity

Dependency no external systems

external systems

container

17

Modern Enterprise Java Apps

•  Integrate with external systems •  SMTP, FTP, LDAP, RDBMS, Web Services, JMS

•  Rely on container-provided functionality •  data sources, connection factories, transaction

managers

18

Effective Integration Testing

•  Fast

•  Repeatable

•  Automated

•  Easy to configure

•  Run out-of-container

19

Out-of-container

•  Zero reliance on availability of external systems

•  Can be run anywhere •  developer workstation •  CI server

•  Approximate the production environment •  Embedded database •  In-memory SMTP server, FTP server, JMS broker

20

Spring TestContext Framework

21

In a nutshell…

The Spring TestContext Framework … provides annotation-driven unit and integration testing support that is agnostic of the testing framework in use … with a strong focus on convention over configuration and reasonable defaults that can be overridden through annotation-based configuration … and integrates with JUnit and TestNG out of the box.

22

Testimony

“The Spring TestContext Framework is an excellent example of good annotation usage as it allows composition rather than inheritance.” - Costin Leau

23

Feature Set

•  Context management and caching

•  Dependency Injection of test fixtures

•  Transaction management

•  SQL script execution

•  Spring MVC and REST

•  Extension points for customization

24

Spring 2.5 Testing Themes

•  @ContextConfiguration –  XML config files –  Context caching

•  @TestExecutionListeners –  Dependency injection: @Autowired, etc. –  @DirtiesContext –  @Transactional, @BeforeTransaction, etc.

•  SpringJUnit4ClassRunner

•  Abstract base classes for JUnit and TestNG

25

Spring 3.x Testing Themes (1/2)

•  Embedded databases –  <jdbc:embedded-database /> &

<jdbc:initialize-database /> –  EmbeddedDatabaseBuilder &

EmbeddedDatabaseFactoryBean

•  @Configuration classes

•  @ActiveProfiles

•  ApplicationContextInitializers

26

Spring 3.x Testing Themes (2/2)

•  @WebAppConfiguration –  Loading WebApplicationContexts –  Testing request- and session-scoped beans

•  @ContextHierarchy –  Web, Batch, etc.

•  Spring MVC Test framework –  Server-side MVC and REST tests –  Client-side REST tests

27

Spring 4.0 Testing Themes

•  SocketUtils –  Scan for available UDP & TCP ports

•  ActiveProfilesResolver API –  Programmatic alternative to static profile strings –  Set via resolver attribute in @ActiveProfiles

•  Meta-annotation support for tests –  Attribute overrides (optional and required)

28

New in 4.1 – Context Config

•  Context config with Groovy scripts

•  Declarative configuration for test property sources

–  @TestPropertySource

29

New in 4.1 – Transactions & SQL

•  Programmatic test transaction management –  TestTransaction API

•  Declarative SQL script execution –  @Sql, @SqlConfig, @SqlGroup

•  Improved docs for transactional tests

30

New in 4.1 – TestExecutionListeners

•  Automatic discovery of default TestExecutionListeners –  Uses SpringFactoriesLoader –  Already used by Spring Security

•  Merging custom TestExecutionListeners with defaults –  @TestExecutionListeners(mergeMode=

MERGE_WITH_DEFAULTS) –  Defaults to REPLACE_DEFAULTS

31

New in 4.1 – Spring MVC Test

•  Assert JSON responses with JSON Assert –  Complements JSONPath support

•  Create MockMvcBuilder recipes with MockMvcConfigurer –  Developed to apply Spring Security setup but can be used

by anyone

•  AsyncRestTemplate support in MockRestServiceServer –  For asynchronous client-side testing

32

Context Management

33

@ContextConfiguration

•  Declared on test class –  Inheritance supported but overridable –  Spring Boot: use @SpringApplicationConfiguration

•  ContextLoader loads ApplicationContext based on: –  Configuration in annotation –  Or by detecting default configuration

•  Supports: –  XML configuration files –  @Configuration classes –  Groovy scripts

34

@WebAppConfiguration

•  Declared on test class

•  Instructs Spring to load a WebApplicationContext for the test

•  ServletTestExecutionListener ensures that Servlet API mocks are properly configured

•  Most often used with the Spring MVC Test Framework

35

@ContextHierarchy

•  Declared on test class –  Used with @ContextConfiguration

•  Configures hierarchies of test application contexts –  Useful for Spring MVC, Spring Batch, etc.

36

@ActiveProfiles

•  Declared on test class –  Used with @ContextConfiguration

•  Configures which bean definition profiles should be active when the test’s ApplicationContext is loaded

•  Active profiles can be configured: –  Declaratively within the annotation –  Or programmatically via a custom ActiveProfilesResolver

37

Context Caching

•  The Spring TestContext Framework caches all application contexts within the same JVM process!

•  Cache key is generated based on configuration in: –  @ContextConfiguration –  @ContextHierarchy –  @WebAppConfiguration –  @ActiveProfiles

•  Use @DirtiesContext to remove a given test from the cache

38

Ex: Context Configuration

@RunWith(SpringJUnit4ClassRunner.class)@WebAppConfiguration@ContextHierarchy({

@ContextConfiguration(classes = RootConfig.class),@ContextConfiguration(classes = WebConfig.class)

})@ActiveProfiles("dev")public class ControllerIntegrationTests {

// ...

39

Dependency Injection

40

DI within Integration Tests

•  Dependencies can be injected into a test instance from the test’s ApplicationContext •  Using @Autowired, @Inject, @PersistenceContext, etc.

•  The ApplicationContext itself can also be injected into test instances… •  @Autowired ApplicationContext •  @Autowired WebApplicationContext

41

EventService Integration Test

@RunWith(SpringJUnit4ClassRunner.class)@ContextConfigurationpublic class EventServiceIntegrationTests {

@Autowired EventService service;

@Test public void save() { Event event = new Event("test event"); Event savedEvent = service.save(event); assertNotNull(savedEvent.getId()); // ...}

42

Transactional Tests

43

Transactions in Spring

•  Spring-managed transactions: managed by Spring in the ApplicationContext –  @Transactional and AOP

•  Application-managed transactions: managed programmatically within application code –  TransactionTemplate and

TransactionSynchronizationManager

•  Test-managed transactions: managed by the Spring TestContext Framework –  @Transactional on test classes and test methods –  Transaction is rolled back by default!

44

Ex: Declarative Tx Management in Tests

@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration@Transactionalpublic class TransactionalTests {

@Test public void withinTransaction() { /* ... */ } What if we want to

stop & start the transaction within the test method?

45

TestTransaction API

•  Static methods for interacting with test-managed transactions

–  isActive() –  isFlaggedForRollback()

–  flagForCommit() –  flagForRollback()

–  end() –  start()

query status

change default rollback setting

end: roll back or commit based on flag start: new tx with default rollback setting

46

Ex: Programmatic Tx Mgmt in Tests @Testpublic void withinTransaction() { // assert initial state in test database: assertNumUsers(2);

deleteFromTables("user");

// changes to the database will be committed TestTransaction.flagForCommit(); TestTransaction.end(); assertNumUsers(0);

TestTransaction.start(); // perform other actions against the database that will // be automatically rolled back after test completes...}

47

SQL Script Execution

48

SQL Script Execution Options

•  At ApplicationContext startup via: •  <jdbc> XML namespace •  EmbeddedDatabaseBuilder in Java Config

•  Programmatically during tests with: •  ScriptUtils, ResourceDatabasePopulator, or abstract

transactional base test classes for JUnit and TestNG

•  Declaratively via @Sql, @SqlConfig, & @SqlGroup •  Per test method •  Per test class

49

Ex: Embedded Database in Java Config

EmbeddedDatabase db = new EmbeddedDatabaseBuilder() .setType(H2) .setScriptEncoding("UTF-8") .ignoreFailedDrops(true) .addScript("schema.sql") .addScripts("user_data.sql", "country_data.sql") .build();

// ...

db.shutdown();

50

Ex: Embedded Database in XML Config

<jdbc:embedded-database id="dataSource" type="H2"> <jdbc:script location="classpath:/schema.sql" /> <jdbc:script location="classpath:/user_data.sql" /></jdbc:embedded-database>

51

Ex: Populate Database in XML Config

<jdbc:initialize-database data-source="dataSource"> <jdbc:script location="classpath:/schema_01.sql" /> <jdbc:script location="classpath:/schema_02.sql" /> <jdbc:script location="classpath:/data_01.sql" /> <jdbc:script location="classpath:/data_02.sql" /></jdbc:initialize-database>

52

Ex: @Sql in Action

@ContextConfiguration@Sql({ "schema1.sql", "data1.sql" })public class SqlScriptsTests {

@Test public void classLevelScripts() { /* ... */ }

@Test @Sql({ "schema2.sql", "data2.sql" }) public void methodLevelScripts() { /* ... */ }

53

@Sql - Repeatable Annotation (Java 8)

@Test@Sql( scripts="/test-schema.sql", config = @SqlConfig(commentPrefix = "`")@Sql("/user-data.sql")public void userTest() { // code that uses the test schema and test data}

Schema uses custom syntax

54

@Sql wrapped in @SqlGroup (Java 6/7)

@Test@SqlGroup({ @Sql( scripts="/test-schema.sql", config = @SqlConfig(commentPrefix = "`"), @Sql("/user-data.sql")})public void userTest() { // code that uses the test schema and test data}

55

Spring MVC Test Framework

56

What is Spring MVC Test?

•  Dedicated support for testing Spring MVC applications

•  Fluent API

•  Very easy to write

•  Includes client and server-side support

•  Servlet container not required

57

Details

•  Included in spring-test module of Spring Framework 3.2

•  Builds on

–  TestContext framework for loading Spring MVC configuration

–  MockHttpServlet[Request|Response] and other mock types

•  Server-side tests involve DispatcherServlet

•  Client-side REST testing for code using RestTemplate

58

Ex: Web Integration Test (1/2) @RunWith(SpringJUnit4ClassRunner.class)@WebAppConfiguration@ContextHierarchy({

@ContextConfiguration(classes = RootConfig.class),@ContextConfiguration(classes = WebConfig.class)

})@ActiveProfiles("dev")public class ControllerIntegrationTests { @Autowired private WebApplicationContext wac; private MockMvc mockMvc; // ...

59

Ex: Web Integration Test (2/2) @Before public void setup() { this.mockMvc = MockMvcBuilders .webAppContextSetup(this.wac).build(); }

@Test public void person() throws Exception { this.mockMvc.perform(get("/person/42") .accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(content().string("{\"name\":\"Sam\"}")); }

60

In Closing…

61

Spring Resources

•  Spring Framework –  http://projects.spring.io/spring-framework

•  Spring Guides –  http://spring.io/guides

•  Spring Forums –  http://forum.spring.io

•  Spring JIRA –  https://jira.spring.io

•  Spring on GitHub –  https://github.com/spring-projects/spring-framework

62

Blogs

•  Swiftmind Blog –  http://www.swiftmind.com/blog

•  Spring Blog –  http://spring.io/blog

63

Q & A

Sam Brannen twitter: @sam_brannen www.slideshare.net/sbrannen www.swiftmind.com

top related