Happy spring everyone! I'm Vlad and today we'll look at the final topic, which is crucial from the perspective of professional development in general and k8s operators and controllers in particular. As a reminder, in the previous article, we started the practical part of our task and wrote a small controller that manages valkey
(open-source redis).
Other articles in the series:
Part 2. Controller Implementation
Testing is a critical stage in the development of any application, as tests provide confidence that everything works as expected. Kubernetes operators and Custom Resource Definition (CRD) controllers are no exception. Quality, multi-level testing ensures the reliability, stability, and predictability of operator behavior under various conditions and usage scenarios.
Kubernetes operators often manage critical resources and processes in the cluster, so errors in their operation can have serious consequences. Properly organized testing helps identify potential problems in the early stages of development.
In this article, we will explore different approaches to testing k8s operators: from simple unit tests to full-scale end-to-end tests in a test cluster environment. We will also discuss tools and frameworks that help automate the testing process and ensure high code quality.
Special attention will be paid to specific aspects of testing CRD controllers, including verification of reconciliation logic, validation of Custom Resource objects, and testing interaction with the Kubernetes API.
All code related to the practical part can be found on our GitHub:
https://github.com/uagolang/k8s-operator
Let's dive a bit (but not too deep) into testing theory to make sure we're all on the same page. While different programming languages have their own names for various types of tests, standardizing them, I would highlight 3 main types.
Unit tests are the basic level of testing that verifies individual functions and methods for correct operation. For more complex cases, table-driven tests are often used. They allow testing a function with different input data and edge cases.
<aside> 1️⃣
When writing unit tests, it's important to follow these practices:
Integration tests are verify the interaction between different system components and their correct operation together. Unlike unit tests that test individual functions in isolation, integration tests verify how different parts of code work together. For the test environment, we'll use the testenv
package from Kubernetes.
<aside> 2️⃣
Characteristics of integration tests:
End-to-end (e2e) tests are the highest level of testing that checks the entire system as a whole, simulating real program usage with real interaction with external services, testing through user interfaces (API endpoints, CLI, etc.) and verifying the entire data flow through the system.
<aside> 3️⃣
Characteristics of e2e tests:
Mocking - is a technique in testing where real objects are replaced with their imitations to isolate the tested code from external dependencies. In Go, there are several approaches to mocking: