Enumerations with associated values are my favorite feature of Swift. But how can we write unit tests against them? “Make them Equatable and use XCTAssertEqual” is common advice.
I’m here to argue otherwise. In fact, let’s use this as a jumping-off point to discuss Swift Equatables in unit tests.
Uncle Bob set off another firestorm with his blog post The Dark Path. Condemnation from the Swift programming community was, well, swift. How dare he insult our wonderful new language? Clearly he’s a n00b who hasn’t done enough Swift programming.
Except that he’s no n00b — not even close. As Mark Seemann said,
Perhaps you disagree with @unclebobmartin (at times I do), but remember: he's been programming all of YOUR LIFE. Don't presume him ignorant.
— Mark Seemann (@ploeh) January 14, 2017
I’m here to defend Uncle Bob’s post, as it relates to unit testing and TDD.
How can we use Test-Driven Development for JSON parsing? Most developers are concerned with ways to implement the production code. There are various approaches, various libraries… But what about the unit test side of things?
If we write effective unit tests, the design can appear incrementally. And with a strong suite of tests, you’re free to change the implementation — even radically. When the results are guaranteed by tests, whatever approach you take or library you use becomes an implementation detail!
Last time, we looked at design principles, such as sticking to the Single Responsibility Principle and returning a Response Model. This time, let’s look at:
When you’re new to Test-Driven Development, there’s a strong tendency to continue writing code the way you used to. Then you step back and ask, “But how can you unit test this? TDD is so impractical!”
Almost always, my answer is: “Then don’t write it like that.”
Apple recently published a blog post, Working with JSON in Swift. I was looking for tips on Swift JSON parsing, and found the beginning of the article quite helpful. But it took a bad turn at the end…
I’ve shown you how to replace real objects with fakes in Swift, so that you can begin creating useful Swift mock objects. We did this by moving away from a concrete type to a protocol. Anything that implements the protocol will work, so fakes are no problem.
But what do we do when we can’t change the signature? How do we substitute fake arguments, or a fake return value?
It’s time to talk about partial mocks in Swift.
Last time, we looked at How Does Swift Support Stubbing and Mocking? Swift’s
extension declaration opens the way, letting us attach new protocols to existing classes. That much is well-known in the Swift community.
But then what? How do we create useful Swift mock objects? I’ve seen many examples that are okay… to start with. But in the long run, I’m afraid they’ll fall short for ongoing maintenance.
I wrote OCMockito because I wanted Objective-C mock objects that struck a better balance between “precise” and “forgiving”. I also wanted test code that was easier to read and write. What can we do with Swift mocking?
You’re writing a unit test in Swift. You feel the need to avoid interactions with a real object. You want to provide a fake object, a mock, or a “test double” (like a stunt double). But Swift is strict about types! How can we do Swift mocking?[This post is part of the series TDD Sample App: The Complete Collection …So Far]
I try to avoid asynchronous tests because they’re slow. But sometimes they’re worth having. When you do have them, it’s worth spending extra effort to make them as fast as possible.
My mistake was that I only focused on the speed of the happy path. Today, I learned a way to improve the speed of failure scenarios, at least around testing network requests.
Test speed matters a great deal. In Test-Driven Development, you want to repeatedly take small, verified steps. Fast feedback is crucial to the process.
But even apart from TDD, test speed is important to keep your whole team moving forward. When someone submits a pull request, your build system builds your system and runs its tests. The time that requires stalls that particular pull request. And the more simultaneous pull requests you have, the worse things get.
Let me rephrase that in a positive way: small wins in test speed can accumulate into big wins for your entire team.
So let’s look at an asynchronous test that does real networking. If you have any tests like this, there may be an opportunity to improve their speed.[This post is part of the series TDD Sample App: The Complete Collection …So Far]
Since 2001, I’ve relied on an understanding of test execution flow in xUnit frameworks. But somewhere along the way, my understanding of the XCTestCase life cycle got messed up. I picked up an assumption that’s just wrong.
At best, it’s an assumption that can bloat our test runs. At worst, it can wreak havoc.
Do you enjoy conferences and workshops? I’m looking forward to attending, teaching, and speaking at these events in the fall of 2016…