📜 ⬆️ ⬇️

Three years of autotests: how to increase speed and not only


Hi, I'm Alexey, a full-stack developer of the Vimbox platform. When I came to Skyeng, they decided here whether it was worth the time to spend on the autotest system and asked me to share my experience from the previous work. And I had such experience: by the time of leaving the previous place we wrote in php and twisted more than 3 thousand tests. As a result, I made a small internal presentation telling about the rake that I managed to tread in a few years of developing these auto-tests, struggling for their speed, code readability and overall efficiency. The presentation seemed to colleagues useful, so I put it in the text to be useful also to a wider audience.


To begin with, the terms that will be discussed in the article:



Pros and cons of different types of tests



Acceptance tests



Unit tests



Functional tests are an intermediate solution.



The fight for speed


At the old work, we wrote a lot of functional tests, and the main challenge was the response speed. I had to wait a long time for the result, even with a local launch on the developer's computer. The speed was so low that it was not possible to apply the “development through testing” approach, since it involves running autotests several times per hour. Found a bottleneck - working with the database. How to deal with this?


Experience first: moki


Mock in PhpUnit is a dynamically created object whose class is dynamically inherited from the parodied class. You can configure what the methods of the moq will return, you can check which methods of the moq how many times with which parameters were called


The main plus of moki - they allow you to cut off whole pieces of functionality. Replacing the service with moch, we get rid of the need to think what is happening there, to develop additional scenarios and fixtures so that everything works correctly. As a result: fewer fixtures, and the response speed is higher due to the fact that we cut off the extra code that executes queries to the database.


The implicit plus of mobs is that they make them better organize dependencies. When you write a code, knowing that it will be necessary to write a test on it, where something is replaced by mokami, you immediately think about dependencies.


Minus : the test code is too attached to implementation. During the test, we must create a mock object and think about what methods should be called on it.


The second minus found is that the tests have become less reliable. They “do not notice” even changes in the interface, not to mention the implementation. Those. we deleted the method somewhere and after a long time found that the tests covering it still work as if nothing had happened, because we saw its mock, and he pretended that everything was fine.


I consider the experience with mokas unsuccessful in terms of speeding up the tests.


Experience Two: SQLite


The next option is SQLite DBMS , it can create a database in RAM. I had to write a PostgreSQL translator schema in SQLite, after each migration a new SQLite schema was generated. Tests from this circuit created an empty database in RAM. This approach increased the speed of tests on local machines by two to four times. It became realistically to run the entire test suite several times per hour.


But there were also disadvantages. We have lost many of the native PostgreSQL features (json, some handy aggregate functions, and more). Queries had to be written so that they worked on both PostgreSQL and SQLite.


Experience Three: PostgreSQL Optimization


This solution was working, but it caused some pain. At some point, we learned that PostgreSQL can be optimized for autotests, which reduces the response time by about four times. To do this, add a few settings to postgresql.conf:


fsync=off synchronous_commit=off full_page_writes=off 

These are reliability settings, they guarantee that if the server dies in the middle of a transaction, it will complete correctly when everything starts working again. It is clear that such settings cannot be made on production, but it was convenient on automatic tests.


This setting is applied to the entire cluster, affects all databases, it cannot be applied to any one database. If you manage to localize the databases in a separate cluster and disable fsync in it, this is very convenient.


A bit about new


I would also like to mention the danger of the new operator. Services created with its help cannot be replaced by mokas and stubs. Conclusion:



Conclusions from three years of experience



')

Source: https://habr.com/ru/post/461901/


All Articles