F.I.R.S.T Principles of Unit Testing
By: Piero Sifuentes
Tags: iOS App Development, Swift Programming, Programming, Unit Testing, Software Development

Running tests in a randomized order also means our system under test (SUT) should also be isolated from its dependencies, we can follow up the techniques described on the previous principle.

On the other hand, each time we create a Unit Test (highlighting Unit) we should follow the rule of the 3A’s, Arrange, Act and Assert (the common way or used for TDD) or the other rule Given, When and Then (used for BDD).

Arrange means build the necesary state for your test case, here’s where all the data and dependencies, mocks or dummies should be provided to test. These vars should be independent from any environment.

Act is where you must invoke the method/property under test. We must just invoke this method/property for unit tests, don’t get confused with the integration tests.

Assert the logical outcome/expectation. At any given point, a unit test should only assert one logical outcome, multiple physical asserts can be part of this physical assert, as long as they all act on the state of the same object.

Remember, the real value of this principle is being able to run any test at any time, in any order.

You may consider also give a chance to BDD (Behavior driven development). This topic is not part of this article, I’ll be talking about BDD in future Articles. Take a look at these great frameworks to implement BDD with Swift.

Repeatable, all our Unit Tests should be Repeatable and Deterministic, this means if we run multiple times one test case, it should produce the same result even if we change the environment conditions like, simulator, OS version, API environment, and other kind of external dependencies. As you can notice, this principle compliments with the previous ones, leading us to implement the faster and independent techniques like have all the input parameters that the SUT requires predefined and hardcoded.

A great example is when we have as input a value from keychain or user defaults. To achieve our Isolation and Repeatable principles we can use a memory key value store service, replacing that key value provider instead keychain as input. As you can see, dependency injection is always our best friend.

Remember and let me repeat it, the real value of this principle is get real feedback no matter the external context or where you run the test cases.

Self validating means that, our tests should self validate, there must not be manual interpretation of results or manual arrange steps before you can run it.

T stands for Thorough but developers who practice test-driven development also spell it as timely Timely.

Thorough means when we implement a unit test, we should consider happy paths and negatives or edge scenarios. We have to create one unit test for the happy path using valid inputs and another for the failure case with invalid inputs (This example only consider 1 happy and 1 failure path, you must consider each path as possible). We should also consider create additional unit tests for cases where we have ranges like MIN and MAX values.

The real value of Thorough Principle is try to cover every use case scenario, covering security, large values, range values, illegal inputs and behaviors, etc. Not guide your unit tests on the Test Coverage value, 100% coverage doesn’t mean your tests are covering you from possible edge scenarios and future issues.

Timely means you can write unit tests at any time, even after release the feature but is better to create unit tests at the time you are working on the feature. If you practice TDD this is part of your coding routine.

Write tests when you are working in the feature will give you an idea of the side paths and it’ll let you map and prepare the dependencies that will be required to be injected. Write tests before releasing the feature will also give you more confidence that the feature will work as expected and decreasing the chances to introduce bugs in production.

You may consider have rules or guidelines on your review process or automated tools (CI) to reject code without enough tests. I don’t recommend create a strict rule around unit tests, like require a specific amount of coverage , but I neither leave the development process without unit tests.

Conclusion

These principles help you to boost your tests to the next level. TDD, BDD, SOLID and other great principle and techniques are needed to improve your unit tests and all your code, give a change and keep reading and learning.

Hope you like this piece and find it helpful. Thanks for reading, and if you wanna give a change to SOLID, here you have my article.

References