Course contentsShow
← Docker, Kubernetes & CI/CD
Lesson 488 of 8027. Package Management and AutomationFree lesson

Testing Controllers with Envtest

Write unit and integration tests for your controller logic using the Envtest framework to simulate a local Kubernetes API server.

In this lesson, you will learn how to validate your custom controller logic by running a real, lightweight Kubernetes API server directly within your test suite using envtest.

Why use Envtest?

When you write a controller, the "truth" of your system lives in the Kubernetes API. Mocking every API call is error-prone and complex. envtest allows you to spin up a binary of the kube-apiserver and etcd locally during your test execution. This lets your controller interact with a genuine API server without needing a full-blown cluster (like KinD or Minikube), making your CI pipeline significantly faster.

Setting up the Environment

In your suite_test.go file, you configure the envtest.Environment. This handles the binaries for the API server and points your controller manager to a local, ephemeral port:

var testEnv *envtest.Environment
var cfg *rest.Config

func TestMain(m *testing.M) {
    testEnv = &envtest.Environment{
        CRDDirectoryPaths: []string{filepath.Join("config", "crd", "bases")},
    }

    cfg, err := testEnv.Start()
    // handle err...

    code := m.Run()
    testEnv.Stop()
    os.Exit(code)
}

Writing the Integration Test

Once the environment is running, your tests can use the client to create custom resources. Because your controller is also watching this same API server, it will trigger its Reconcile loop automatically when you create, update, or delete objects.

To verify logic, you simply perform an action and use Eventually blocks to poll for the expected state:

func TestReconcile(t *testing.T) {
    // 1. Create a Custom Resource
    myObj := &myv1.MyResource{...}
    Expect(k8sClient.Create(ctx, myObj)).To(Succeed())

    // 2. Assert the controller modified the resource
    Eventually(func() bool {
        err := k8sClient.Get(ctx, key, myObj)
        return err == nil && myObj.Status.Ready == true
    }, time.Second*5, time.Millisecond*250).Should(BeTrue())
}

By leveraging envtest, you confirm that your controller reacts correctly to real Kubernetes events, ensuring your logic handles edge cases—like resource ownership and status updates—accurately before you ever deploy to a production cluster.

Key Takeaway: Envtest provides an ephemeral, local API server that allows you to test your controller's reconciliation logic against actual Kubernetes state without the overhead of a full cluster.