Navigating the testing terrain, tools and techniques across modern product development phases.
Starting with the development phase, testing aides in product development with tools designed to facilitate test-driven development, which emphasizes the first principle of SOLID Principles, namely the ‘single responsibility’ Principle.
Essentially, the code consists of unit functions that have a single responsibility. This single responsibility is tested by unit tests which ensure that the behaviour of the functions remains constant as the software grows and evolves as well as function is used and reused over time.
TDD also encourages loosely coupled systems with less dependency and the possibility of container-managed dependencies injection. This is particularly important in modern-day OOPS-based applications in which tight coupling between OOPS components is an antipattern.
Special mention goes out to Mockito which as its name suggests works in helping Object Mocking.
- Code Mocking
Mocking is a way to test the functionality of a class in isolation by stripping off its dependency on other classes using appropriate mocking tools. The mocking tool helps by injecting the required dependent class by means of mock objects. The framework provides an assembled object, and the mock object can also return predefined values when certain methods are invoked on it.
The following are some examples of mocked services:
- An object managing a database.
- An object representing external data like a CSV.
- An object representing a Network service.
- Any other API or service.
Mocking does not require a database connection, or the properties file read, or the file server read to test a functionality. Mock objects do the mocking of the real service. Using a mock framework, a dummy object is returned based on some dummy input passed to it.
Here is a brief example:
Consider building a service that returns the price of the companies stock. During development, for unit testing the live stock service cannot be used to get real-time data. So, we need a dummy implementation of the stock service as below.
Code to demonstrate the mocking using the Mockito framework
import java.util.ArrayList;
import java.util.List;
import static org.mockito.Mockito.*;
public class PortfolioTester {
public static void main(String[] args){
//The portfolio object which is tested
Portfolio portfolio = new Portfolio();
//Preparing the Portfolio For Testing
List<Stock> stocks = new ArrayList<Stock>();
Stock googleStock = new Stock("1","Google", 10);
Stock microsoftStock = new Stock("2","Microsoft",100);
stocks.add(googleStock);
stocks.add(microsoftStock);
//Create the mock object of stock service class by the means of a Mocking method "mock"
StockService stockServiceMock = mock(StockService.class);
// below is the an example of mocking the behavior (method calls) of stock service to return the value of stock price when a method invocation happens
when(stockServiceMock.getPrice(googleStock)).then Return(50.00);
when(stockServiceMock.getPrice(microsoftStock)).thenReturn(1000.00);
//add stocks to the portfolio
portfolio.setStocks(stocks);
//set the stockService to the portfolio
portfolio.setStockService(stockServiceMock);
double marketValue = portfolio.getMarketValue();
//verify the market value to be
//10*50.00 + 100* 1000.00 = 100500 an annotation can check this at runtime. And hence validate the Market value calculation
}
}
Below features are supported by the Mockito mock framework:
- Return value support − Returns a value by the method belonging to the mocked object.
- Exception support − Throws the exception when the mock code corresponding to the method is executed.
- Order check support − When a mock is executed, it calls a chain of methods in turn.
- Annotation support — Support for providing the mock with meta information for its execution.
Other Mocking Frameworks that assist in Unit Testing are below:
Ref:-http://www.sotwaretestinghelp.com
Tests extend all the way to deployment, where they act as gatekeepers, validating all code before it enters a deployed environment and as a precursor step to CI/CD.
2. API Mocking
In the day of microservice development system integration and interface contracts are of prime importance. Therefore, tools that mock services and interface contracts help in agnostic development and decouples dependency between systems being developed.
Some of the Primary Mocking frameworks and reference links are listed below:
a) PostMan: A very versatile and widely used API testing tool.
https://www.g2.com/products/postman/reviews
b) CloudShare: A Effective tool for mocking software functions and features.
https://www.g2.com/products/cloudshare/reviews
c) ReadyAPI: A reliable tool for testing SOAP and REST API.
https://www.g2.com/products/readyapi/reviews
d) Tricentis Tosca: AI powered testing tool to test components in isolation.
https://www.g2.com/products/tricentis-tosca/reviews
e) Mockoon: A simple API testing and mocking tool.
https://www.g2.com/products/mockoon-mockoon/reviews
f) Wiremock: A versatile testing tool for mocking REST API.
Due to the comprehensiveness of this tool and completeness of the solution, this is the preferred tool in the industry.
Below considerations helped us make the decision of using WireMock.
Among the API mock tools mentioned above, a conscious choice needs to be made considering the various parameters like:
1) Usage Scenario.
2) Open Source.
3) Cost if any to modify the tool to meet the requirements of the development team.
4) API mocking, latency-timed responses and exception handling.
5) Community Support.
6) Compatibility with large landscape or eco system.
When to use open-source tools: Open-source tooling is one of the good way to avoid vendor lock-in, to customize the solution according to your requirements and save on the licensing costs.
Limitations: OSS Tools tend to have a steep learning curve and are geared towards developers who are willing to put in the time and effort. Regular maintenance and upgrade is required in a self hosted OSS application.
Consequences
Once the team has a mastery on the open-source tool, in this case WireMock, the team could utilize the server responses in Rest Clients, Java Client (Client library also offered as FOSS). This framework is not only cost-effective in scenarios where each API call to the production system is expensive, but also assists in the decoupling of development teams once the API contract is chosen.
3. Performance Mocking
At higher granularity and from the performance perspective, we use load testing tools such as JMeter Load Runner to test the application and APIs.
A load to performance matrix based on controlled load can be prepared to determine the capacity of the server required to host the application.
A transparent view of bottlenecks that slow down the system, the system’s internal workings and interactions between components can be seen in the application’s behaviour under concurrent access, stress and endurance tests, and spike tests.
4. UI Mocking
Following the completion of development and testing, it’s time to scrape the website using Selenium-like test tools and record the application’s behavior in different scenarios. Selenium helps in number of ways including cross browser compatibility. Automating regression tests saves hours of functional testing and provides quick and automated reports on the build’s stability.
Conclusion
Even though it may take an initial time investment and to achieve these benefits, implementing testing and mocking practices will lead to a reduction in defects, an improvement in overall product quality, and a significant reduction in turn around time. Detecting bottlenecks, errors, and non-compliances early helps build efficient, secure, scalable solutions in a systematic manner.