The practice of testing backend for Java + Rest-Assured

    In a previous article, I shared my automation experience on the Robot Framework. Now we will talk about a slightly different approach to testing the API for a project on Kotlin.

    Taking advantage of the freedom to choose a stack of technologies and relying on the desire to try something “in battle”, I turned to Rest-Assured. Not without some difficulties, my colleagues and I started the tests, and following the results of mastering the approach, we wrote it down to the list of key tasks of this kind.

    image

    (image used on parody rights)

    It all started with the fact that we received a request to automate API testing on one of the new projects in the Ad-tech segment . We did Campaign Manager, DMP and several integrations with third-party systems. And the testers had an extremely simple task: to automate the snook testing for further integration into CI and constant monitoring of the status of this API, since third-party systems are tied to it and the correctness of the work is critical. In this case, verification of business logic was not required, since the service being tested is essentially a proxy interface.

    Why Rest-Assured?


    From the point of view of test automation, we managed to work in various areas - UI, web, mobile, desktop, backend, REST API, SOAP. The previous project gave us quite a lot of experience on the Robot Framework, so it would be most logical to use it. Most of the testing team are familiar with it, and if an urgent replacement of a specialist is required, this will be done quickly and practically painlessly. But a different decision was made.

    First, the project itself was written in Kotlin and was collected using Gradle. At the same time, at the design stage, it was decided not to single out autotests into a separate project. As noted in the comments to the previous article, gluing Java (Kotlin) and Robot Framework is a big pain, so there was no point in contacting RF. Plus, looking back at work with the robot, it was interesting for me to try a different approach. Moreover, on this project we could independently choose a stack of technologies - the business did not set its own conditions.

    In search of ideas, I turned to our development team, as well as colleagues from testing, and CTO advised you to look at Rest-Assured ( rest-assured.io). After I read the documentation and sample tests in open sources, the approach offered by Rest-Assured seemed to me very attractive. It implies receiving a response from the backend as JSON, which we will deserialize into good old Java objects.

    Further with this structure it is possible to work as with a normal object. As a result, we have a completely normal object-oriented approach for validating the compliance of an API response with the described object structure. As a bonus, we get a fast failproof test of the response structure - if the object obtained by deserializing the API response is different in the number of fields or their names, the tests will drop even before the data is checked with an error of deserialization. So we will understand, we need to repair the backend or update the tests in accordance with the new API requirements. In our case, this was important because, as I mentioned above, many third-party subsystems are tied to the API.

    For accuracy, I note that approximately the same failproof test could be obtained on RF, but in a slightly different way. However, the story today is not about that. Personally, I was more comfortable and clearer to go by Rest-Assured with an entity that has certain fields and methods.

    Attempt at writing


    Before starting to use the stack on a real project, I decided to try it on a small CRUD-service. In order not to practice my own mistakes right away, I decided to look for best practices on this stack and quickly found an article by Philip Hauer , where he reflected his automation experience on Rest-Assured. After studying the article to write a working version of the tests of my service was not difficult. They turned out simple, easy to read and understandable.

    To battle!


    The project started, and when the first response structures were described, the preparation of test documentation and writing autotests began. To understand the overall picture, I’ll give you a full stack of autotests:

    • Java
    • JUnit4 - execution and parameterization of test scenarios (standard annotation @Parametrize),
    • Rest-Assured - building and executing queries,
    • AssertJ - validation of received values,
    • Allure - reporting building
    • Gradle - build
    • Jackson - deserialization.

    When the first tests were written, the problem of correct parameterization became apparent. Transmitting simple data values ​​and expected results seemed extremely inefficient and ugly. I did not have time to solve this problem before the holidays, but my colleagues, who were attracted during my absence, dealt with it. For a beautiful and easy-to-read parameterization, they decided to make a base class with functions to add, get, and delete parameters of an object from which all classes inherited, whose objects were used to call the appropriate API methods.

    image

    This allowed literally on the fly to create the necessary data and transfer them to the test parameters.

    image

    Rest-Assured allows you to deserialize the response to the desired class. The resulting answer is decomposed into a previously known structure using Jackson. Classes for deserialization look as simple as possible - all the expected fields with their types are described.

    image

    Further simple work with objects and assertion of concrete fields and their values ​​proceeds.
    The most difficult and unobvious thing I encountered in this approach is the inability to pass to Rest-Assured as one of the null parameters (the result is a fall in NullPointerException). Apparently, this is a known problem, but the developer is not going to correct the situation, recommending either to send the field empty or not to send it at all. We encountered this problem already at that stage when the basis of the project was ready and it was necessary only to add test classes. Therefore, just a little corrected their code.

    In general, I liked the approach. It is curious that after a while it began to be applied on the project of another customer (though not with our filing). And we put the stack for automation of API testing (JUnit + AssertJ + Rest-Assured) into the category of key projects for Java / Kotlin. In Python, it will be illogical to pull it, since it is better that the competences of development and testing overlap.

    It is also worth noting that one of the advantages of this solution lies in its scalability and adaptability to complex logic. So, it is best suited for serious projects, where it really makes sense to describe large objects, clean code and block architecture, when there are individual pieces responsible for preparing, transmitting and receiving data in a readable form, as well as subsequent verification of data for compliance some conditions. In small projects, all this is meaningless.

    Results


    In about a month we managed to automate about 250 tests and provide the required level of coverage. Of course, after the completion of the automation process, an internal presentation was held for all comers, so that employees had an idea of ​​the work done and could learn from the experience gained on this project.

    The author of the article: Dmitry Masters

    PS We publish our articles on several sites of the Runet. Subscribe to our pages on the VK , FB or Telegram channel to find out about all our publications and other news from Maxilect.

    Also popular now: