Effective Testing in Complex Software Development Projects
CEO and Founder at Amoniac OU
Manual Or Automatic Testing?
The software is invariably created by people, tested by people and, in most cases, used by people. The worst dream of any responsible tester is to miss a serious bug. The tester tries carefully examines the requirements and writes test cases, carefully checks the product, and after the release, the user reports a critical problem within a week.
How many bugs that are obvious to others are missing? And, maybe, it's time to work only with automatic testers?
Automatic testers or QA
Automated tests catch errors earlier, preventing them from ever being deployed. They offer a faster feedback loop for programmers because they do not need to go through each path in their application manually. A well-written test can take milliseconds, and with a good development setup, you don’t even have to leave your editor.
If you compare this with the manual approach a hundred times a day, you can save a good chunk of time. This allows developers to more quickly implement functions since they can confidently write code without opening a browser.
When applications grow without a reliable test suite, frequent errors silently penetrate their code. And as the application grows, the overall solution is to scale the number of hands on the deck — hiring specialized testers (QA), which will never be as effective as automated tests in trapping regressions.
QA increases the time it takes to implement features because developers must communicate with each other with another person. Compared to a set of tests, it's expensive.
This does not mean that QA is absolutely useless, but they should be hired in addition to a good test suite, and not as a replacement. Although hand-held testers are not as effective as computers when searching for regressions, they are much better at testing the subjective qualities of software, such as user interfaces.
Types of Tests
Let's look at the different types of tests. At one end is unit tests. These tests isolate individual components, proving that they provide the expected behavior regardless of the surrounding system. Because of this, unit tests are usually small and fast.
In the real world, these components do not exist in a vacuum: they must interact with each other. One component can expect a collaborator to have a specific interface if, in fact, he has a completely different one. Despite the fact that all tests pass, the software as a whole is broken.
Here are the integration tests. These tests use the system as a whole, rather than its individual components. They usually do this by simulating a user trying to complete a task in software. Instead of accessing call methods or collaborators calls, integration tests relate to clicking and typing as a user.
The best way to create your own test set, using a combination of tests. This is a suite that contains several high-level integration tests that cover the overall functionality of the application, several middle-level tests that cover the subsystem in more detail, and many unit tests to cover the details of each component.
This approach corresponds to the strength of each type of test when trying to minimize their disadvantages, for example, a slow execution time.
Development process stages
Test Driven Development Process
Automated tests are probably the best way to gain confidence in a growing code base. To increase this confidence and achieve big gains in time saving and clean code, it is recommended to write code using a process called Test Driven Development. TDD is a process that uses tests to develop designs and applications. It starts with the Red, Green, Refactor development cycle.
Red, Green, Refactor is a series of steps that lead to the development of this function or the correction of an error.
When solving problems with TDD, you need to decide where to start testing the code. Starting from a high level, checking how the user interacts with the system, and then turn to zero? Or start with a low-level development and move towards the final function? The answer will vary from person to person and function to function.
If a test is originally written, it does not mean that test development is used. When performing a Red, Green, Refactor cycle, it is important to write code only in response to error messages that result from testing failures. This ensures that functions that are not tested will not be implemented.
Behavior Driven Development Process
The software development methodology Behavior Driven Development is an offshoot from Test Driven Development.
The main idea of this methodology is to combine in the process of developing purely technical interests and business interests, thereby allowing management staff and programmers to speak the same language. For communication between these sides, natural language constructs understandable to a non-expert is used, such as admin panels, registration forms that usually express the behavior of a software product and the expected results.
The BDD methodology is an extension of TDD in the sense that before writing any test, you must first describe the desired result of the added functionality in a subject-oriented language. After this is done, the constructions of this language are translated by experts or special software into the test description.
Domain Driven Design
BDD can also be described as the intersection between Domain-Driven Design (DDD) and TDD. Domain-Driven design is an approach to software development aiming to deal with projects with complex business rules where collaboration between developers and domain experts (typically, this role is assumed by the client) is necessary to set a common language and a domain model that can be translated into very specific and detailed requirements. In BDD, these specific requirements are used to drive the development process in the first step of its cycle.
From business to tech testing process
What Do Our Guys Use For Testing?
For our team, testing is first and foremost a good tone rule. We created our own set of tools and applications and didn’t give up on manual testing at all, which in our opinion is considered optimal in the work of each IT company.
Let's review the tools we have chosen for testing.
To verify Ruby code, use a tool written in Ruby RSpec. This is a behavior-based development environment (BDD) and writing sufficient code (TDD). The entire work of the Amoniac team aimed at the clarity of development and the satisfaction of the end customer. That is why We selected RSpec because we consider it the best and most effective tool in our testing work.
Turnip is an open source Ruby gem that provides a platform for acceptance tests and aims to solve some of the issues faced when writing specifications with Cucumber. Cucumber supports various programming languages and is also very popular as an acceptance testing framework.
Turnip works like Cucumber as it is a framework that primarily supports acceptance testing. Although Turnip is not as feature-rich as Cucumber, it is simple and powerful, which makes acceptance testing easier and more accessible.
3. FACTORY BOT
Factory Bot is a helper for writing factories for Ruby tests. It was previously known as Factory Girl. For older versions, use FactoryGirl instead of FactoryBot.
This library is used to conveniently create instances of models, something on which we will test. For example, some Users, and Articles, and Projects, and with Task. We cannot create objects every time by filling in all required fields. This is where the Factory Bot will come in handy. It is enough to define a pattern once and then generate new entities based on it.
Approach for preventing external requests is to record a live interaction and ‘replay’ it back during tests. The VCR gem has a concept of cassettes which will record your test suites outgoing HTTP requests and then replay them for future test runs.
Considerations when using VCR:
- Communication on how cassettes are shared with other developers.
- Needs the external service to be available for a first test run.
- Difficult to simulate errors.
The VCR gem is really useful if you have methods that need to make an API request. You don’t want to make API requests during tests, especially if the API has some kind of rate limit. What you could do is create a text file mocking the response you get from the web service you’re making the API to and do the tests that way, or you can use the VCR gem.
WebMock is a library for stubbing HTTP requests and setting expectations on HTTP requests in Ruby. With WebMock, developers can match requests based on method, URI, headers, and body, and match the same headers in different representations.
And in the end, we can easily say that yes, testing is a huge lion's share of the time saved as by the developer and as the end client. It is this work that allows you to make exactly the product you see in a head in the end, and this is a guarantee to a client that it works flawlessly.
Set of tools are capable of testing in seconds and in this case, writing a test will be a time saving and not vice versa. Writing a test gives error messages, the test that will tell you what to do next. And, perhaps, it looks like a kind of robotization, but with a growing number of projects and their scale, it becomes just a necessity.
But should never forget that on the way of testing there can be a significant number of traps and anti-patterns that should be avoided, because a poorly written test can have the opposite effect and lead to a crash.
The test gives you confidence that you can move on. Both software and QA could and should be used together to tame existing projects and solve larger and more complex ones!
Subscribe to get your daily round-up of top tech stories!