Git Product home page Git Product logo

spring-boot-testing's Introduction

Spring Boot Testing

Overview

This course has covered the following aspects:

  • Unit Testing
  • Integration Testing
  • Testing External Services (Stripe)
  • Mocking with Mockito
  • Test Driven Development -TDD

Architecture Diagram

  • The diagram shows the different units tested in isolation as well as the integration test that covers the whole system.

    diagram

Tests Coverage

coverage

tests_passes

Some test code

  • Testing the PaymentRepository class using the settings with @DataJpaTest.
@DataJpaTest //to test JPA queries
class PaymentRepositoryTest {

    @Autowired
    private PaymentRepository underTest;

    @Test
    void itShouldSavePayment() {
        //Given
        long paymentId = 1L;
        Payment payment = new Payment(paymentId,
                "card",
                "donation",
                new BigDecimal(10),
                EUR,
                UUID.randomUUID());

        //When
        underTest.save(payment);

        //Then
        Optional<Payment> optionalPayment = underTest.findById(paymentId);
        assertThat(optionalPayment)
                .isPresent()
                .hasValueSatisfying(
                        p -> assertThat(p).usingRecursiveComparison().isEqualTo(payment)
                );
    }
}
  • Testing the CustomerService class using @Mock and @Captor.
@ExtendWith(MockitoExtension.class)
class CustomerServiceTest {
    @Captor
    private ArgumentCaptor<Customer> customerArgumentCaptor;

    @Mock
    private CustomerRepository customerRepository;

    @Mock
    private PhoneNumberValidator phoneNumberValidator;

    @InjectMocks
    private CustomerService underTest;

    @Test
    void itShouldSaveCustomer() throws NumberParseException {
        //Given

        // .. phoneNumber
        String phoneNumber = "600000000";

        // .. a customer request
        CustomerRegistrationRequest request = new CustomerRegistrationRequest(
                "Amador", phoneNumber
        );

        // given a valid number (mock)
        given(phoneNumberValidator.validate(phoneNumber)).willReturn(true);

        // ... no customer found with that phone number (mock)
        given(customerRepository.findCustomerByPhoneNumberNative(phoneNumber))
                .willReturn(Optional.empty());

        //When
        underTest.registerNewCustomer(request);

        //Then
        then(customerRepository).should().save(customerArgumentCaptor.capture());

        Customer customer = customerArgumentCaptor.getValue();
        assertThat(customer).isNotNull();
        assertThat(customer.getName()).isEqualTo("Amador");
        assertThat(customer.getPhoneNumber()).isEqualTo(phoneNumber);
    }
}
  • Testing the StripeServiceTest class mocking static method with Mockito
@ExtendWith(MockitoExtension.class)
class StripeServiceTest {

    @Captor
    private ArgumentCaptor<PaymentIntentCreateParams> paramsArgumentCaptor;

    @Captor
    private ArgumentCaptor<RequestOptions> requestOptionsArgumentCaptor;

    private StripeService underTest;

    @BeforeEach
    public void setUp() {
        underTest = new StripeService();
    }

    @Test
    void itShouldChargeCard() {
        //Given
        String method = "method";
        String description = "description";
        BigDecimal amount = new BigDecimal(10);
        Currency currency = EUR;

        // Mock the PaymentIntent and Charge
        PaymentIntent paymentIntentMock = mock(PaymentIntent.class);
        Charge chargeMock = mock(Charge.class);

        // Set up the behavior for the mock objects
        given(paymentIntentMock.getLatestChargeObject()).willReturn(chargeMock);
        given(chargeMock.getPaid()).willReturn(true);


        try (MockedStatic<PaymentIntent> paymentIntentMockedStatic =
                     Mockito.mockStatic(PaymentIntent.class)) {

            //Mock the static method call
            paymentIntentMockedStatic.when(() -> PaymentIntent.create(
                            any(PaymentIntentCreateParams.class),
                            any(RequestOptions.class)
                    )
            ).thenReturn(paymentIntentMock);

            //When
            CardPaymentCharge cardPaymentCharge =
                    underTest.chargeCard(method, amount, currency, description);

            //Then
            assertThat(cardPaymentCharge).isNotNull();
            assertThat(cardPaymentCharge.isCardDebited()).isTrue();

            // .. capture the arguments passed to the static method
            paymentIntentMockedStatic.verify(() -> PaymentIntent.create(
                    paramsArgumentCaptor.capture(),
                    requestOptionsArgumentCaptor.capture()
            ));

            //validate params
            PaymentIntentCreateParams paramsArgumentCaptorValue = paramsArgumentCaptor.getValue();
            assertThat(paramsArgumentCaptorValue.getAmount()).isEqualTo(amount.longValue());
            assertThat(paramsArgumentCaptorValue.getCurrency()).isEqualTo(currency.name().toLowerCase());
            assertThat(paramsArgumentCaptorValue.getDescription()).isEqualTo(description);
            assertThat(paramsArgumentCaptorValue.getPaymentMethod()).isEqualTo(method);

            //validate request options
            RequestOptions requestOptionsArgumentCaptorValue = requestOptionsArgumentCaptor.getValue();
            assertThat(requestOptionsArgumentCaptorValue.getApiKey()).isEqualTo("sk_test_CGGvfNiIPwLXiDwaOfZ3oX6Y");
        }
    }
}
  • Testing the PaymentIntegrationTest class using @SpringBootTest and @AutoConfigureMockMvc that allows to make HTTP calls to Controllers.
@SpringBootTest //It starts the application instead of testing separately
@AutoConfigureMockMvc //Needed to test endpoints
class PaymentIntegrationTest {

  @Autowired
  private CustomerRepository customerRepository;
  
  @Autowired
  private MockMvc mockMvc; //test RESTful API

    @Test
    void itShouldCreatePaymentSuccessfully() throws Exception {
        //Given

        // .. a customer request
        String phoneNumber = "600000000";
        CustomerRegistrationRequest customerRequest = CustomerRegistrationRequest.builder()
                .name("Amador")
                .phoneNumber(phoneNumber)
                .build();

        // a payment request
        String method = "method";
        String description = "description";
        BigDecimal amount = new BigDecimal(10);
        Currency currency = EUR;
        PaymentRequest paymentRequest = PaymentRequest.builder()
                .paymentMethod(method)
                .paymentDescription(description)
                .amount(amount)
                .currency(currency)
                .build();

        //When
        ResultActions resultCustomerRequestActions = mockMvc.perform(post("/api/v1/registration")
                .contentType(MediaType.APPLICATION_JSON)
                .content(new ObjectMapper().writeValueAsString(customerRequest)) //json object
        );

        // get the customerId after insertion in db (client does not send any id)
        Optional<Customer> optionalCustomer = customerRepository.findCustomerByPhoneNumberNative(phoneNumber);
        UUID customerId = null;
        if (optionalCustomer.isPresent())
            customerId = optionalCustomer.get().getId();


        ResultActions resultPaymentActions = mockMvc.perform(post("/api/v1/payment/{customerId}", customerId)
                .contentType(MediaType.APPLICATION_JSON)
                .content(new ObjectMapper().writeValueAsString(paymentRequest))
        );

        //Then
        resultCustomerRequestActions.andExpect(status().isOk());
        resultPaymentActions.andExpect(status().isOk());

        // assertions using get endpoint
        MvcResult mvcResult = mockMvc.perform(get("/api/v1/payment")).andReturn();

        String jsonResponse = mvcResult.getResponse().getContentAsString();

        List<Payment> payments = new ObjectMapper().readValue(jsonResponse, new TypeReference<>() {
        });

        assertThat(payments.size()).isEqualTo(1);
        //get the payment
        Payment payment = payments.get(0);

        assertThat(payment.getPaymentDescription()).isEqualTo(description);
        assertThat(payment.getPaymentMethod()).isEqualTo(method);
        assertThat(payment.getAmount().longValue()).isEqualTo(amount.longValue());
        assertThat(payment.getCurrency()).isEqualTo(currency);
        assertThat(payment.getCustomerId()).isEqualTo(customerId);
    }
}

spring-boot-testing's People

Contributors

amadr-95 avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.