4.18 Unit Test There and Back Again Part 1

In part one I explain how y'all can improve the architecture of your app to make it better unit testable.

Writing tests should be as much fun equally writing code, correct? Just why isn't it? That's what I asked myself and I noticed that every time I tried to write some tests, I didn't know where to begin or what to test. And if I had an thought, it turned out I couldn't test it or I didn't know how to test it.

Later a while I started to realise that if you take a clear structure of your code, you get to know where to put what in your code and it'south condign clear what to test. In role 1 you can read how to construction your code. In this office you can read what you can exam and how you lot can examination it.

In general adept tests are flexible just not frail, which ways that if you change one line of code, it should not suspension lots of tests. Your tests should be all-encompassing, comprehend all border cases and run fast. So you lot tin can run them often and get feedback as quick as possible.

Structure of a unit test

In a test yous can distinguish a subject that you're going to examination, inputs and outputs . Information technology's good to place these three dissimilar parts because they assist you to effigy out what you need to do with them. For example y'all will never stub your exam subject area, but a dependency you lot tin. You will need as much tests as possible input sets to test their outcomes. And the values of the outputs are verified in the assertions of the exam.

The typical construction of a unit test is:

  • Given
  • When
  • Then

In the Given you create mocks and prepare inputs, in the When you execute the method to test on your subject and in the And so yous verify the outputs with assertions.

Different types of examination doubles

To create real blackness boxes for our tests we might want to mask some parts of our implementation. Nosotros tin exercise this with so-called examination doubles from which there are different kinds.

When you must pass an argument in your test, just yous know it will never be used in the method being tested, tin can pass a dummy . Information technology doesn't matter what the dummy returns.

When you need a dummy that returns a specific value because the balance of the arrangement relies on it to continue running the test, the dummy is chosen a stub .

If you but desire to test if a method is called you lot tin use a spy . A downside is that the more than stuff yous spy, the tighter you lot couple your tests with the implementation of your app.

A mock is a spy that has assertions within of information technology. It checks what function is called with what arguments, when and how often.

The concluding season we have is a imitation . All exam doubles discussed so far don't care about what arguments you pass in. However a simulated does, because information technology has business logic that gives different outputs for unlike inputs.

Add unit of measurement test files to your projection

To add a unit examination file to your Xcode project y'all can cheque unit of measurement tests at the start of a new projection, or you lot can add a test target to an existing project later on. Click on your project in the Project Navigator, add a new target and choose a Unit Testing Parcel:

1

At the tiptop of the file you need to import XCTest and make your app target available for testing by adding @testable import YourTarget.

Your form needs to inherit from XCTestCase. In that location is already a setUp() method to do some initialisation or grooming before a examination and a tearDown() method to do some cleanup later on a test and then tests will not interfere with each other. These methods are called before and afterwards each test. Remember that the unit tests are running randomised, and so the society will always alter. Likewise don't forget to call super in these methods first.

Finally you can write the actual tests. These are written as methods which always need to start with the word test.

Put your test information in one file

To challenge yourself to notice the right name for your test-data and prevent doubles, I recommend to put your testdata into ane file. I chosen it Seeds and information technology can look like this:

2

Test the Interactor

The subject under test (sut) in this test is the ListMoviesInteractor. So the Interactor is the black box that gets it'south inputs from the View Controller.

The test inputs are the methods defined in the ListMoviesBusinessLogic protocol: func fetchMovies()

The test outputs are the methods defined in the ListMoviesPresentationLogic and in the MoviesWorker protocol:

3

Nosotros actually demand to examination if both these outputs are chosen. What happens inside them we don't care for now. We will test that when we arrive there. So we can make examination doubles of them. To test if both methods are chosen I replace the presenter and the worker with spies. This substitution lasts only until the finish of the exam method, so if we would accept more tests we would need to ready these test doubles again at the begin of each test.

4

A exam method should test i thing and the proper noun should fully describe what the test is about. So I seperate the tests for calling the presenter and the interactor. In the Given I set up the spy for the worker to check if it's method is called. Then I initialise the Interactor with the Presenter and the Interactor spy.

When I call the method fetchMovies(), the input of the exam, on the subject field under test: the interactor. In the And so I do the affirm to check if the method in the worker was chosen (via the spy)

5

Similar is the exam to check if the Presenter is chosen past the Interactor:

6

You lot can likewise exam if the correct (amount of) movies are handed over to the presenter:

7

Test the Presenter

The setup of this examination class is like to the interactor but instead the subject under exam (sut) is at present the ListMoviesPresenter. The input of this test is the presentFetchedMovies(_ movies: [Movie]) method from the ListMoviesPresentationLogic protocol. The outputs are the methods divers in the ListMoviesDisplayLogic protocol, in this case the displayFetchedMovies(_ movies: [ListMoviesViewModel]) method.

8 9

Next to this test we want to exam if the formatting of the viewModels from the models is correct. I will do this in a test for the viewModel extension. Adjacent to that we will test when we call the presentFetchedMovies(_ movies: [Movie]) method, we will receive the same amount of viewModels back as models we gave as an argument.

10 11

Test the View Controller

Too participating in the VIP cycle, the View Controller too interacts with the user interface via IBOutlets and IBActions. IBActions are the inputs of the View Controller and IBOutlets are the outputs. Next to that, external things may need to happen when the view loads, appears or disappears. These view lifecycle events are too inputs to the View Controller.

For our View Controller we will check these 3 different kinds of possible inputs we need to test:

1) view lifecycle methods:

 In viewDidLoad() the method fetchMovies() is invoked to make a request to

 the interactor.

2) methods in the ListMoviesDisplayLogic protocol:

 displayFetchedMovies(_ movies: [ListMoviesViewModel])

iii) IBAction methods: none

The setUp() and tearDown() methods of our tests will exist extended with some logic for the view. To make certain the view bureaucracy is clean at the starting time of each exam we create a new UIWindow object in setUp() and set it to naught in tearDown(). We then set up the sut by instantiating the View Controller. Finally there is a loadView() method that volition add the View Controller'due south view to the window.

The process of bringing the view onto screen does have fourth dimension and information technology's possible the view may not have been fully loaded when your examination starts running. When addSubview() is called, the view update events are queued and executed when the run loop gets a gamble to run. To solve this timing outcome, you can call RunLoop.electric current.run(until: Date()) to wait with the examination for the next tick in the execution cycle. This is important in our instance when nosotros test lifecycle events as viewDidLoad().

12

For the kickoff test we phone call loadView() in Given to become the view bureaucracy fix. We then invoke sut.viewDidLoad() in the When. In the And then phase, we assert that fetchMovies() is called by creating the ListMoviesBusinessLogicSpy like we did similarly before for the Interactor and Presenter and check if its variable is prepare to true.

13

In the second examination we want to test if the orders are displayed. This is done past the reloadData() method in Apple tree's UITableView. Then we demand to make certain that this method is called. We can make a spy for that also past creating a subclass of UITableView.

14

In the test nosotros gear up the Tabular array View to the TableViewSpy and call the displayFetchedMovies(_ movies: [ListMoviesViewModel]) method that should trigger the reload.

15

Besides these tests we can write a few tests to check if the number of sections returns 1 and if the number of rows of the Table View is equal to the number of viewModels passed back to the View Controller:

16

The last affair we want to test if all the items of the viewModel are correct displayed in the right views of the Table View Prison cell. Because nosotros have one viewModel we only check section 0 and row 0 in this example.

17

Running the tests

To build your tests in Xcode 9 you can get to Product > Build for > Testing (⇧⌘U) or yous can run them and choose Product > Exam (⌘U). In the Test Navigator (⌘vi) yous can meet the results of you tests. If you accept run the tests in one case you can see little diamonds before each test in your testfiles. If you lot only want to re-run ane examination, you can click on the icon in front of it which will alter in a play-icon when you hover over it. Or if yous want to re-run all tests of one class you can click the icon in front of the test class. In View > Debug Area > Testify Debug Surface area y'all can come across the test logs. It shows the number of passes and failures and how long it takes to run each exam and all the tests.

If you take run the tests, you can go to the Report Navigator (⌘9), click on the last tests then on Coverage. You volition encounter that except for the initialisation of the View Controller everything is tested for 100%. If you don't see any coverage go to Production > Schemes > Edit scheme. So become to Test and the tab Options. If y'all put a checkmark in front of Gather coverage so you can see the coverage the adjacent fourth dimension you have run the tests.

18

You can also visit below for the original weblog posts and yous might want to "handclapping" Jeroen!

https://medium.com/@ Jeroen deVrind/how-to-write-better-unit-tests-in-swift-c172f0bf943

https://medium.com/@ Jeroen deVrind/how-to-write-ameliorate-unit of measurement-tests-in-swift-function-2-4e2b91aaa1da

elliswithaticking.blogspot.com

Source: https://www.icemobile.com/how-to-write-better-unit-tests-in-swift-part-2

0 Response to "4.18 Unit Test There and Back Again Part 1"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel