I'm trying out test driven development in a toy project. I can get the tests working for the public interface to my classes (although I'm still on the fence because I'm writing more testing code than there is in the methods being tested).
I tend to use a lot of private methods becuase I like to keep the public interfaces clean; however, I'd still like to use tests on these methods.
Since Cocoa is a dynamic language, I can still call these private methods, but i get warnings in my tests that my class may not respond to these methods (although it clearly does). Since I like to compile with no warnings here are my questions:
Access Control You probably know that you can apply the testable attribute to an import statement in a test target to gain access to entities that are declared as internal. import XCTest @testable import Notes class NotesTests: XCTestCase { ... }
Unit Tests Should Only Test Public Methods The short answer is that you shouldn't test private methods directly, but only their effects on the public methods that call them. Unit tests are clients of the object under test, much like the other classes in the code that are dependent on the object.
You can't test private methods in Swift using @testable . You can only test methods marked either internal or public . As the docs say: Note: @testable provides access only for “internal” functions; “private” declarations are not visible outside of their file even when using @testable.
Strictly speaking, you should not be writing unit tests that directly test private methods. What you should be testing is the public contract that the class has with other objects; you should never directly test an object's internals.
Remember that there's actually no such thing as "private methods" in Objective-C, and it's not just because it's a dynamic language. By design, Objective-C has visibility modifiers for ivars, but not for methods — it's not by accident that you can call any method you like.
@Peter's suggestion is a great one. To complement his answer, an alternative I've used (when I don't want/need a header just for private methods) is to declare a category in the unit test file itself. (I use @interface MyClass (Test)
as the name.) This is a great way to add methods that would be unnecessary bloat in the release code, such as for accessing ivars that the class under test has access to. (This is obviously less of an issue when properties are used.)
I've found this approach makes it easy to expose and verify internal state, as well as adding test-only methods. For example, in this unit test file, I wrote an -isValid
method for verifying correctness of a binary heap. In production, this method would be a waste of space, since I assume a heap is valid — I only care about it when testing for unit test regressions if I modify the code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With