Introduction and Context Setting

Welcome to the second lesson in our journey into Test-Driven Development (TDD) using Go and Testify. In the previous lesson, we discussed how to utilize dummies to isolate dependencies. In this lesson, we will shift our focus to another kind of test double — Stubs.

By the end of this lesson, you'll understand what stubs are and how to implement them in your tests using Go, specifically for isolating dependencies like external services.

Understanding Stubs in Testing

In testing, test doubles help us isolate parts of our application. We've previously discussed dummies. Stubs, a more useful type of test double, provide predefined answers to method calls during testing. Unlike other test doubles, stubs aren't concerned with tracking usage; they are simple yet powerful for specific scenarios.

Stubs are especially useful when testing functions that rely on external services or complex dependencies. By simulating function outputs, stubs make tests faster and more predictable. Stubs focus on ensuring your application's logic functions as expected without verifying the correctness of external dependencies.

Example: Crafting a `WeatherAlertService` Using Stubs

To demonstrate the concept of stubs, we will create a WeatherAlertService using stubs in a test-driven development process with Go.

Getting Ready to Test

We'll build a WeatherAlertService that fetches data from a WeatherService. This service will issue alerts based on specific conditions. Relying on the actual data source is impractical for testing, so we'll use stubbed data instead.

Red: Writing the First Test

Create a new test file named weather_alert_service_test.go with the following test setup:

In this test:

  • We create a manual stub WeatherServiceStub that simulates weather data by setting predefined values for Temperature and Conditions via the SetWeather method.
  • The stub’s GetCurrentWeather method returns a WeatherData struct with these predefined values, simulating expected weather conditions for the test scenario.
  • The Testify library is used to assert whether the WeatherAlertService correctly interprets the weather data and returns the appropriate alert, specifically checking for a heat warning when the temperature exceeds 35 degrees.

Run this test, expecting it to fail initially, as WeatherAlertService has yet to implement the logic for handling these conditions.

Green: Making the Test Pass

Implement the WeatherAlertService struct with minimal logic. Create the weather_alert_service.go file:

Run the tests again. The objective is to pass this specific test scenario by implementing only the necessary logic, avoiding overengineering other cases.

Refactor: Introduce a Stub Using the Mock capability

In the initial implementation, we created a manual stub, WeatherServiceStub, to simulate weather data. Now, we will refactor this by leveraging the Testify library to streamline the process and improve maintainability. Using the "mock" package from Testify, we can create flexible and reusable stubs with minimal code.

The "mock" package allows us to set up method expectations and return values dynamically. By substituting our hand-crafted stub with a Testify-based one, we achieve the same test outcomes but with enhanced clarity and simplicity. This approach decreases the potential for bugs and makes adjusting test parameters easier.

Here's how we refactor our WeatherAlertServiceTests:

  • Replace the WeatherServiceStub with a mock.Mock.
  • Use the On method in Testify to define the expected inputs and outputs for the GetCurrentWeather method.
  • Through Testify, we eliminate the need to manage state explicitly within our custom stub class.

The refactored test class using Testify's "mock" package is shown below:

Summary and Preparation for Practice

In this lesson, we explored the concept of stubs and how they can be a practical method to isolate dependencies in tests using Go. Key takeaways:

  • Stubs allow us to replace external dependencies by providing predefined return values, facilitating the testing of features that rely on services beyond our immediate control.
  • Through the Red-Green cycle, we emphasized writing tests that initially fail and implementing just enough logic to pass the tests.

Prepare to apply these techniques in forthcoming exercises, where you will explore different scenarios using stubs, which will enhance your skills in employing test doubles and adhering to TDD, ultimately advancing your ability to create dependable, thoroughly-tested code.

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal