Context. It all depends on context!

I.?????????????Intro

I have often been asking if I know REST API and if I can test API (automation/manual). Do I have enough knowledge to write automated tests?

I was stunned by such questions from the people reading my resume. At first, I tried to do something with it: to say what I could answer questions about the difference between PUT and PATCH, what status codes exist, and what category they belong to, but alas - I think I could not prove these people even the fact that I am a human being, which means I can think and learn.

It's not about the resume; the point is that the employer wants to confirm all the skills you have mentioned in your resume. Context is very important!

I decided that arguing was ineffective, and I thought, why not write a small demo showing my programming and testing skills?

GitHub project with source code: https://github.com/YuriiChukhrai/http-status-codes-demo.

What is the idea behind the demo?

Write a REST API that will only do two things:

1) display help information about the HTTP code of interest (JSON/XML);

2) simulate a response with the desired status code - for example, you sent a request about code 100 and received an HTTP response of code 100 and its description.

And we will cover all this with tests: unit and integration. TestNG will run all these tests, and the results will be presented in the generated Allure report (with attached request/response context).

It seems simple. And so we will briefly describe how all this will work for us. We will need Spring Boot + Maven + TestNG + Rest-Assured.

Pic#1. The handling of requests

Pic#1. The handling of requests


The design of Spring-Boot application for [HTTP codes demo]

Pic#2. The design of SpringBoot application for [HTTP codes demo]

Incoming requests will be processed in REST controllers (annotation @RestController):

  • InfoController - provides general information about the project, the current version, and so on.
  • HttpCodeControllerImpl - CRUD (Create Read Update Delete) service for reference information on status codes.
  • ExampleResponseController - mimics the status code we need and gives information about it.

These controllers will call the service class [HttpCodeServiceImpl] (@Service annotation), which will process them according to business logic. If the service class needs to interact with the database, it can do this through the [HttpCodeCustomRepositoryImpl] class. This is additional customization to the standard JpaRepository interface.

II.?????????????Small context

Before diving into the details, let's go over the additional tools we'll use. After creating the database, we need to fill it with some information.

2.1 Flyway - SQL migration

Flyway is an open-source tool that helps you implement automated and version-based database migrations. It allows you to define the required update operations in an SQL script or as Java code. Flyway detects the required update operations and executes them.

So, you don’t need to know which SQL update statements need to be performed to update your current database. You and your co-workers just define the update operations to migrate the database from one version to the next. And Flyway detects the current version and performs the necessary update operations to get the database to the latest version. Resource: https://thorben-janssen.com/flyway-getting-started/

Flyway integration (Maven/pom.xml)

<dependency

??? <groupId>org.flywaydb</groupId>

??? <artifactId>flyway-core</artifactId>

??? <version>${flyway.version}</version>

</dependency>>        

Here is the configuration:

1)???flyway.enabled=true - we enable this support in the Spring project (after adding the dependency to pom.xml);

2)???flyway.locations=classpath:resources/db/migration - specify the location of files for migration.

?2.1.1 Flyway migration

The file name follows Flyway’s default naming convention: V<VERSION>__<DESCRIPTION>.sql. This file contains the SQL statements for database version 1, and Flyway will store it with the description “create_database” in the SCHEMA_VERSION table.

?

This is what the files for SQL migration look like:

?????./src/main/resources/db/migration/V1_1__create_http_codes_table.sql - contains instruction for creation of schemas;

?????./src/main/resources/db/migration/V2_1__insert_http_codes_table.sql - fill the data in the tables.

2.2 Database (H2)

We will use H2 like a database (https://www.h2database.com/html/quickstart.html). This DB uses the RAM for storage - this is great for our purposes. It can be easily changed to any other DB by changing the config in settings:

?????spring.jpa.database-platform

?????spring.datasource.url

?????spring.datasource.driverClassName

?????spring.datasource.username

?????spring.datasource.password

?????spring.h2.console.enabled

You can check/view the database when the project is running by following the link ( https://localhost:{port}/h2-console )


No alt text provided for this image

Pic#3. DB - Access to the H2 console in a browser


No alt text provided for this image

Pic#4. Content of the DB table [HTTP_CODE] in H2

2.3 Lombok

Project Lombok is a mature library that reduces boilerplate code with easy-to-use annotations. The library works well with popular IDEs and provides a utility to “de-lombok” your code by reverting—that is, adding back all the boilerplate that was removed when the annotations were added. It can be useful for making your code more concise, reducing the chance of bugs, and speeding up development time. The size of the Java classes reduced significantly – just add an annotation for your Getters or Setters. Or we can use the Java record introduced in the JAVA 16.

No alt text provided for this image

Pic#5. HttpCode entity/POJO/model representation with JPA and Lombok annotations


III.?????????????More of Context.

For convenience, all examples will be given in MediaType.APPLICATION_JSON, but the API supports XML too (don't forget to specify Accept: application/xml in HTTP Headers). Let's briefly describe each of the controllers.

3.1 InfoController

a) method: Info getGeneralInformation() – has no input parameters and returns the fields with the description of the given project (Info – response entity/POJO/model implemented by Java recod).

Request:

GET {uri}/api/v1/info

Response (200 - OK):


{ 
  "app_name": "HTTP status codes. Demo",

? "app_version": "0.0.1",

? "http_codes_size": 66,

? "dev": "Yurii Chukhrai",

? "e_mail": "[email protected]",

? "git_hub_url": "https://github.com/YuriiChukhrai",

? "linkedin_url": "https://www.dhirubhai.net/in/yurii-c-b55aa6174",

? "swagger_url": "https://server:port/context-path/swagger-ui.html",

? "openapi_url": "https://server:port/context-path/v3/api-docs",

? "openapi_yaml_url": "https://server:port/context-path/v3/api-docs.yaml"

}        


No alt text provided for this image

Pic#6. InfoController and Java Records for entity/POJO/model


3.2 HttpCodeControllerImpl

a) method: HttpCode getHttpCodeByCode(Integer code) - receives the HTTP code of interest as input and returns the [HttpCode] entity/POJO/model containing reference information about it. We will use the CRUD (Create Read Update Delete) principle. I placed all the codes that I could find here and here in the database (V2_1__insert_http_codes_table.sql), so let's start by looking at GET (read). For example, I want to get information about status code 101:

?

Request:

GET {url}/api/v1/http/code/info?code=101

Response (200 - OK):


{????? 
   "id" : 2,

???"code" : 101,

???"category" : "1** Informational",

???"reason_phrase" : "Switching Protocols",

???"definition" : "This code is sent in response to an Upgrade request header from the client and indicates the protocol the server is switching to."

}        

b) method: HttpCode getHttpCodeById(Long id) - receives the ID of the [HttpCode] model in the DB as input and returns the [HttpCode] entity/POJO containing reference information about it.

Request:

GET {url}/api/v1/http/code/3

Response (200 - OK):

{
????? "id" : 3,

????? "code" : 102,

????? "category" : "1** Informational",

????? "reason_phrase" : "Processing",

????? "definition" : "This code indicates that the server has received and is processing the request, but no response is available yet."

}        

c) method: List<HttpCode> getAllHttpCodes() - does not receive any input parameters - returns a collection of all available status codes.

Request:

GET {url}/api/v1/http/code/info/all

Response (200 - OK):

[
????? {

????????????????? "id" : 1,

????????????????? "code" : 100,

????????????????? "category" : "1** Informational",

????????????????? "reason_phrase" : "Continue",

????????????????? "definition":"This interim response indicates that the client should continue the request or ignore the response if the request is already finished."

????? },

????? {??????????

????????????????? "id" : 2,

????????????????? "code" : 101,

????????????????? "category" : "1** Informational",

????????????????? "reason_phrase" : "Switching Protocols",

????????????????? "definition" : "This code is sent in response to an Upgrade request header from the client and indicates the protocol the server is switching to."

????? }

????? ....

]        

The remaining methods will not be difficult to understand by their names:

? HttpCode saveHttpCode(HttpCode newHttpCode) - create a new object [HttpCode] in DB

? HttpCode putHttpCode(HttpCode newHttpCode, Long id) - update a previously created object in the database.

? void deleteHttpCode(Long id) - deleting an object from their database.


3.3 ExampleResponseController

a) method: ResponseEntity<HttpCode> getResponseEntityById(Integer code) - получает статус код, ответ которого надо симулировать, тело ответа - справочная информация о статус коде.

Request:

GET /api/v1/http/code/example/{code}

Response (XXX - xxx: status code depends on input).

No alt text provided for this image

Pic#7.a (JSON) Response in Postman - ExampleResponseController#getResponseEntityById()


No alt text provided for this image

Pic#7.b (XML) Response of ExampleResponseController#getResponseEntityById()


3.4 SpringDoc / OpenAPI / Swagger UI

3.4.1 Spring Doc / Open API

SpringDoc — a tool that simplifies the generation and maintenance of API docs based on the OpenAPI 3 specification for Spring Boot applications. SpringDoc-OpenApi works by examining an application at runtime to infer API semantics based on Spring configurations, class structure, and various annotations. Automatically generates documentation in JSON/YAML and HTML format APIs. This documentation can be completed by comments using Swagger-API annotations.

No alt text provided for this image

Pic#8. Spring Boot configuration Bean for OpenAPI documentation

The ability of APIs to describe their own structure is the root of all awesomeness in OpenAPI. Once written, an OpenAPI specification and Swagger tools can drive your API development further in various ways.

The springdoc-openapi dependency already includes Swagger UI, so we're all set here.

We can simply access the API documentation at:

URL (JSON): https://localhost:7777/v3/api-docs

No alt text provided for this image

Pic#9. OpenAPI documentation JSON (it’s how Mozilla parses JSON by default)

Documentation can be available in YAML format as well, on the following path: /v3/api-docs.yaml

URL (YAML): https://localhost:7777/v3/api-docs.yaml

No alt text provided for this image

Pic#10. OpenAPI documentation YAML

3.4.2 Swagger UI

Swagger is a set of open-source tools built around the OpenAPI Specification that can help you design, build, document, and consume REST APIs. Swagger UI – renders OpenAPI specs as interactive API documentation. Use Swagger UI to generate interactive API documentation that lets your users try out the API calls directly in the browser.

URL: https://localhost:7777/swagger-ui/index.html

No alt text provided for this image

Pic#11. Swagger UI. Endpoint information


No alt text provided for this image

Pic#12. Swagger UI. Schemas descriptions


IV. Test Coverage

4.1 Integration (E2E). Rest-Assured

The tests are based on the Rest-Assured library. These tests represent E2E and can be moved to a separate repository and be part regression suite. As you can see, we start our Spring Boot application in the method [beforeSuite()]. REST-assured was designed to simplify the testing and validation of REST APIs and is highly influenced by testing techniques used in dynamic languages such as Ruby and Groovy.

Location: core.yc.qa.test.e2e.InfoControllerTest

No alt text provided for this image

Pic#13. Spring Boot server + Rest-Assured


4.2 Integration (MockMVC)

These integration tests are implemented using native Spring Boot tools like: [WebApplicationContext and MockMvc] by using annotation for auto wire. The test was implemented for ExampleResponseController endpoints. It’s you use the context, including the up-and-running DB and MockMVC, to mock server requests/responses. MockMVC class is part of the Spring MVC test framework, which helps in testing the controllers explicitly starting a Servlet container. Tests with MockMvc lie somewhere between unit and integration tests.

Location: core.yc.qa.test.integration.ExampleResponseControllerTest

No alt text provided for this image

Pic#14. Spring Boot Test. MVC - ExampleResponseControllerTest


4.3 Integration (Mockito + MockMVC)

These integration tests are implemented using native Spring Boot tools like: [WebApplicationContext and MockMvc] by using annotation for auto wire. But we are not using real DB for that; instead of that, I will use the Mockito framework to mock all requests related to the [httpCodeRepository] (class – responsible for working with the DB) and inject that behavior into [httpCodeService] class. Mockito is a mocking framework used for effective unit testing of JAVA applications. Mockito is used to mock interfaces so that a dummy functionality can be added to a mock interface that can be used in unit testing.

Location: core.yc.qa.test.integration.mock.InfoControllerTest

No alt text provided for this image

Pic#15. Spring Boot Test. Mockito + MockMVC - InfoControllerTest


4.4 Integration (Mockito only)

In this suite, implemented examples of the pure Mockito tests without any of the SpringBootTest/MockMvc injections – we will use the Mockito listener [MockitoTestNGListener.class] for that. DB - will be mocked - [httpCodeRepository] (class – responsible to work with the DB) and [httpCodeService] class.

Location: core.yc.qa.test.integration.mock.HttpCodeServiceImplTest

No alt text provided for this image

Pic#16. Mockito. HttpCodeServiceImplTest

4.5 Integration (Rest-Assured + WireMock)

These tests are mostly like the E2E, implemented by using the Rest-Assured test framework. Instead of bringing up the real server, I decided to provide examples with WireMock library.

WireMock is an HTTP mock server. At its core, it is a web server that can be primed to serve canned responses to requests (stubbing) and that captures incoming requests so that they can be checked later (verification).

This approach will allow you to start to develop your test automation based on the specification long before the dev will complete their part – be more proactive ?.

Location:

a)???core.yc.qa.test.e2e.mock.HttpStatusCodeTest

b)???core.yc.qa.test.e2e.mock.PersonTest

No alt text provided for this image

Pic#17. Rest-Assured + WireMock


4.6 Allure report

I love Allure. It’s open source; it’s beautiful; It has nice features [Steps; Attachments; Links and Tms] – What also do you need for good report and triage?

No alt text provided for this image

Pic#18. Allure report with all test suites and attachments (including the MockMvc requests)


References

https://github.com/allure-framework

https://mermaid-js.github.io/mermaid

https://www.restapitutorial.com/httpstatuscodes.html

https://developer.mozilla.org/en-US/docs/Web/HTTP/Status

https://spring.io/guides/tutorials/rest

https://www.baeldung.com/spring-boot-h2-database

https://www.baeldung.com/spring-response-status

https://howtodoinjava.com/spring-boot2/h2-database-example

https://www.codegrepper.com/code-examples/whatever/responseentity+with+status+code+and+message

https://stackabuse.com/how-to-return-http-status-codes-in-a-spring-boot-application

https://www.baeldung.com/spring-boot-testing

https://www.baeldung.com/spring-test-pyramid-practical-example

https://www.baeldung.com/spring-mock-mvc-rest-assured

https://allaroundjava.com/unit-testing-spring-rest-controllers-mockmvc/

https://mkyong.com/spring-boot/spring-rest-validation-example/

https://www.freecodecamp.org/news/unit-testing-services-endpoints-and-repositories-in-spring-boot-4b7d9dc2b772/

https://howtodoinjava.com/spring-boot2/testing/spring-boot-mockito-junit-example/

https://blog.devgenius.io/spring-boot-deep-dive-on-unit-testing-92bbdf549594

https://reflectoring.io/unit-testing-spring-boot/

https://www.tutorialspoint.com/spring_boot_h2/spring_boot_h2_unit_test_service.htm

https://medium.com/backend-habit/integrate-junit-and-mockito-unit-testing-for-service-layer-a0a5a811c58a

https://projectlombok.org/

https://www.oracle.com/corporate/features/project-lombok.html

https://springdoc.org/#Introduction

https://swagger.io/docs/specification/about/

要查看或添加评论,请登录

Yurii C.的更多文章

  • Multi OpenAPI documentation

    Multi OpenAPI documentation

    I. Intro You are probably already familiar with microservices, how good it is to have them (the more, the better :) )…

  • Test Automation for Mainframe

    Test Automation for Mainframe

    Today, automation must be an integral part of producing any software product, even at the initial development stage. It…

    2 条评论
  • Implementation of custom HTTPS sender for JMeter and InfluxDB

    Implementation of custom HTTPS sender for JMeter and InfluxDB

    Objective Cyber Security - today everyone is concerned about it, whether you are just a user or a company. This topic…

  • Selenide - sugar for Selenium.

    Selenide - sugar for Selenium.

    Do not fear. This is not one of many articles about the Selenium framework.

社区洞察

其他会员也浏览了