Testing Patterns

目次

  • Test ?
  • Experimentation & results

Test ?

Unit Test

Pros

Easy to write

Provide a spec for components

Great for pure components

 

Cons

Heavy use of mocking

Hard to isolate test from implementation

Inputs

Outputs

Application

INTEGRATION Test

Pros

Provide a spec for application

Implementation agnostic

Test API

 

Cons

Dependencies mocking

Performance overhead

Harder to debug

Inputs

Outputs

Application

END2END Test

Pros

Test complete integration

Implementation agnostic

User interactions

 

Cons

Dependencies mocking

Environment setup

Performance overhead

Harder to debug

Unstable

 

User inputs

Webpage

Application

Front

My Frustration

Inputs

Outputs

Application

Test

Inputs

Outputs

Application

Test

Mock

Mock

Mock

Inputs

Outputs

Application

Test

Mock

Mock

Mock

Test

SETUP

Inputs

Outputs

Application

Handling Database

  • In memory or Real -> H2 in memory database
  • Migration scheme  -> Liquibase
  • Fixtures                     -> SQL Script
  • Tests conflicts         -> Rollbacks
@RunWith(SpringRunner.class)
@Transactional
@AutoConfigureMockMvc
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class AccountRestControllerIntTest {

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private ObjectMapper mapper;

    @Test
    @WithMockBasicAuth(principal = "test@test.com")
    public void test_get_user_accounts() throws Exception {
        MvcResult result = mockMvc.perform(get("/account")
            .contentType(MediaType.APPLICATION_JSON)).andReturn();

        Account[] accounts = mapper.readValue(result.getResponse().getContentAsString(), Account[].class);
        Assert.assertEquals(1, accounts.length);
        Assert.assertEquals("Compte Chéque", accounts.get(0).name);
    }
}

Handling External Service

  • Use a Mock Server
  • Use a Mock SMTP Server
    private ClientAndServer mockServer;

    @Before
    public void startMockServer() {
        mockServer = startClientAndServer(9999);
        mockServer.when(request().withMethod("GET")
            .withPath("/users/me/connections").withQueryStringParameter("expand"))
            .respond(response().withStatusCode(200)
            .withBody("{\"connections\": [{\"id\": 505}], \"total\": 1}"));

    }

    @After
    public void stopMockServer() {
        mockServer.stop();
    }

Bonus

  • You can test your API without swagger
  • Refactoring doesn't impact test