TDD in Swift: How to Write Code That Doesn't Break

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

"Test First — Code Later": Why It Works in Swift?

\n\n

Have you ever rewritten the same module for the third time because "it needed to be shipped urgently"? Or caught a bug in production that could have been easily prevented during the writing phase? If so — welcome to the world of TDD (Test-Driven Development).

\n\n

Test-driven development is not just a trendy methodology. It's a way of thinking that forces you to formulate how the code should behave before you write it. In Swift, with its strong typing and powerful XCTest framework, TDD becomes a reliable shield against regressions and unexpected crashes.

\n\n

In this article, we'll break down TDD with real-world examples, write tests for the networking layer and data model, and most importantly — understand how to implement this practice without pain. Let's go!

\n\n

Red-Green-Refactor: The Magic of the Cycle

\n\n

The foundation of TDD is a three-step cycle:

\n\n
    \n
  • Red — write a test that fails (because the code doesn't exist yet).
  • \n
  • Green — write the minimum code to make the test pass.
  • \n
  • Refactor — improve the code without changing its behavior (tests protect you).
  • \n
\n\n

Seems simple? Let's try it in Swift.

\n\n

First Test: Checking the User Model

\n\n

Let's say we have a simple user model. We want it to correctly format the full name. First — the test:

\n\n
import XCTest\n@testable import MyApp\n\nfinal class UserTests: XCTestCase {\n    \n    func testFullName_GivenFirstNameAndLastName_ReturnsFormattedString() {\n        // Arrange\n        let user = User(firstName: "Anna", lastName: "Karenina")\n        \n        // Act\n        let fullName = user.fullName()\n        \n        // Assert\n        XCTAssertEqual(fullName, "Anna Karenina", "Full name should consist of first and last name separated by a space")\n    }\n}\n
\n\n

Run it — the test fails (red). The compiler complains that User doesn't exist. Perfect, that's the intention.

\n\n

Now write the minimum code to pass the test:

\n\n
struct User {\n    let firstName: String\n    let lastName: String\n    \n    func fullName() -> String {\n        return "\\(firstName) \\(lastName)"\n    }\n}\n
\n\n

Run it — green! Now you can move on to refactoring. For example, add handling for empty strings or a middle name. But don't rush — the tests will tell you when it's needed.

\n\n

Testing the Asynchronous Networking Layer

\n\n

One of the most common problems in iOS development is working with the network. TDD is especially useful here because you explicitly separate logic from network calls.

\n\n

Writing a Protocol and a Mock Object

\n\n

First, let's define what our service should look like:

\n\n
protocol WeatherServiceProtocol {\n    func fetchWeather(for city: String, completion: @escaping (Result<Weather, Error>) -> Void)\n}\n
\n\n

Now — the test. We don't want to depend on a real API, so we create a mock:

\n\n
class MockWeatherService: WeatherServiceProtocol {\n    var shouldReturnError = false\n    var mockWeather: Weather?\n    \n    func fetchWeather(for city: String, completion: @escaping (Result<Weather, Error>) -> Void) {\n        if shouldReturnError {\n            completion(.failure(NetworkError.serverError))\n        } else if let weather = mockWeather {\n            completion(.success(weather))\n        }\n    }\n}\n\nfinal class WeatherViewModelTests: XCTestCase {\n    \n    func testFetchWeather_Success_UpdatesModel() {\n        // Arrange\n        let mockService = MockWeatherService()\n        mockService.mockWeather = Weather(temperature: 25.0, condition: "sunny")\n        let viewModel = WeatherViewModel(service: mockService)\n        let expectation = XCTestExpectation(description: "Waiting for weather data to load")\n        \n                

Blogs

Book Recommendations