Test Automation in the “Microservice” Oriented Enterprise
How we got here…
One of the goals of an agile process is to make quality a first-class citizen in the software development process. We talk about testing when we plan feature development, but testing professionals are not included in the discussions when we talk about application architecture and design. This is a missed opportunity.
In the next few paragraphs, we’ll explore evolution of software design from the perspective of a testing professional with the goal of giving an understanding of high-level application architecture and then provide a few options for testing.
The Monolith
Our applications have evolved. We started with monolithic, all-in-one systems that are fairly easy to write and fairly simple to test. But as we add more code (even in a time-boxed agile process), our testing effort is always increasing.
When we deploy, we always deploy everything – even if we didn’t change it.
We found ourselves in a state where it’s pretty easy to write code and testing is a solved problem, but the time to test is always increasing. Therefore, getting code to production is now quite an effort in unpredictable time.
(There are also development and architectural problems with a monolithic approach to applications that we will not get into at this time.)
Our answer was to make our applications smaller.
Service-oriented Applications (SOA)
In moving to SOA, we broke apart our applications into their logical subsystems and treated each subsystem as a separate application, so each application now has much smaller scope and vastly less code to test. We still have the problem of an ever increasing code base, but it’s more manageable.
Each application connects to any dependant applications over some type of common communications structure; HTTP is very popular for this purpose. So when each application requires some functionality from another application, it simply makes a request over that common communication structure…which led us to the dreaded, “Spaghetti Diagram.”
Our applications were now simpler, but their interactions were vastly more complex, making testing them very difficult. We traded a tightly coupled monolith for a tightly coupled enterprise application and we didn’t really have the skills to test at the network layer in our testing professionals. Because of the tight-coupling and unknown dependencies, it was still tough to test and get into production.
Shared Messaging Infrastructure
An answer to tightly-coupled SOA applications is to use a “Shared Messaging” infrastructure to orchestrate the interaction between components. Applications in the system simply generate messages and await responses, while the enterprise infrastructure manages routing messages and responses.
The content of the payloads that are passed between the two are governed by the enterprise application team and agreed on as a standard of communications. These agreements are often called contracts.
Other benefits include;
- No point-to-point integrations
- Loosely coupled, highly scalable systems
- Loosely coupled TEAMS
- Easier to test
- Easier to change
- Technology flexible
Two common examples are below.
Enterprise Service Bus (ESB)
Systems that use an ESB utilize a software package to route messages and provide process orchestration between components.
ESBs can be quite effective but they are expensive, hard to maintain, require specialized skills and are hard to test.
Event-Driven Architecture (EDA)
An alternative approach to the ESB is EDA. In EDA, applications interact by producing and consuming messages that are distributed by an event channel (usually queues). Conceptually, individual applications react to events that occur in some other application by processing the resultant message. In EDA an event typically represents a “significant change in state 2.”
In these messaging-based infrastructures, we gain the smaller applications that we tried to get in SOA that are easier to design and test with loose-coupling between sub-systems that make it easier to test applications in isolation.
Because of the messaging infrastructure, our application teams are free to build large applications or microservices, utilizing the technologies that are best suited for the job. Our enterprises can be a combination so long as all applications obey the contracts for messaging.
Many modern applications that utilize a service based architectural design pattern will typically utilize an ESB or EDA.
Testing
Our approach to testing internal application functionality doesn’t change, but what does change is how we do integration testing. The contracts give us the ability to test in isolation because we know the format of what we produce and consume. We use the contract to test system integration at its “Edges.” But – these are not standard testing approaches. It’s important for the tester to understand how the applications are constructed and how they interact with each other. The tester might need an additional set of skills that are more technical in nature. Once you have developed these skills, a whole new world of testing capability becomes available to you.
Terminology
It becomes important for the tester to know in detail certain terminology around these design patterns.
- Http verbs and headers
- ReST
- API
- Messaging
- Contracts
- Messaging Infrastructure
- Asynchronous integration
- Loosely Coupled
- Application “Edges”
- Mocking and Faking
- Dynamic scaling
- Data consistency, Master Data Management
Tooling
To test these applications, we need to find their edges and test at those boundaries, by passing messages in and examining the messages that are generated. There are several tools available that aid in this testing. These tools generally fall into two categories: manual and automated.
Manual
Manual testing tools allow the tester to construct messages, send then to the component and see the output. Two common tools are Fiddler and Postman.
- Fiddler – more granularity, more technical
- Postman – more friendly user interface.
Automated
Automated testing tools allow tests to be assembled into a suite and run together without manual intervention. A common approach is to use a Domain Specific Language like Gherkin and its most popular implementation of Cucumber.
Determining which approach will work for your team and backlog should be a collaborative effort. Spend some time researching the design patterns, terminology and tooling and you should be better equipped to provide testing value to your team in a microservices oriented world.