2
\$\begingroup\$

I'm studying unit testing in swift and I would like to know if I'm doing the right way.

Here I have the model

struct ChangePasswordRequest: Encodable {
    var email: String
    var newPassword: String
    var token: String
}

And here the unit test

import XCTest
@testable import MyProject

class ChangePasswordRequestTests: XCTestCase {

    var changePasswordRequest: ChangePasswordRequest!

    override func tearDown() {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
        changePasswordRequest = nil
        super.tearDown()
    }

    func testChangePasswordRequest() {

        // given
        let email = "abc@def.com.br"
        let newPassword = "abc123"
        let token =
        """
        rF1rHbYVCpcfyo6K2e7Q68QvKYdeOMt0vDXYehggGU3kx8XiuGmQylXabxbGAyUmSK9RnbL
        """

        // when
        changePasswordRequest = ChangePasswordRequest(email: email, newPassword: newPassword, token: token)

        let requestJSON = """
        {"email":"\(email)","token":"\(token)","newPassword":"\(newPassword)"}
        """

        changePasswordRequest = ChangePasswordRequest(email: email, newPassword: newPassword, token: token)
        guard let encodedRequest = try? JSONEncoder().encode(changePasswordRequest) else {
            XCTFail()
            return
        }

        // then
        XCTAssertEqual(String(data: encodedRequest, encoding: .utf8)!, requestJSON, "Any JSON key differs from model.")

    }

}

I never worked with unit test. It's possible to improve this test?

\$\endgroup\$
2
\$\begingroup\$

Some hints on Unit tests.

  • Use dependency injection to make testing easier
  • Create mocks to eliminate all external dependencies in tests
  • Test units of code (functions, methods, classes)

Example of testable class:

class UserManager: UserManagerType {
 let database: DatabaseType
 init(database: DatabaseType) {
  self.database = database
 }

 func getUser(withId id: String) -> User? {
    return database.getItem(withPredicate: "id == \(id)")
 }

 func getAdmins() -> [User] {
    return database.getItems(withPredicate: "type == admin")
 }
}

protocol DatabaseType { 
   func getItems(withPredicate predicate: String) -> [User]
   func getItem(withPredicate predicate: String) -> User?
} 

Tests:

// create mock for database.
// Try to avoid any external dependencies in tests
class DatabaseMock: DatabaseType {
 var itemsToReturn: [User] = []
 var userToReturn: User?

 func getItems(withPredicate predicate: String) -> [User] {
   return itemsToReturn
 }

 func getItem(withPredicate predicate: String) -> User? {
   return userToReturn
 }
}

// actual test case
class UserManagerTests: XCTestCase {
  var database: DatabaseMock = DatabaseMock()
  var manager: UserManager!
  // setup before each test
  func setUp() {
    database = DatabaseMock()
    manager = UserManager(database: database)
  }

  func testReturnsCorrectUserForId() {
    let expectedUser = User(id: "123")
    database.userToReturn = expectedUser
    let actualUser = manager.getUser(withId: "123")
    XCTAssertNotNil(actualUser)
    XCTAsseerEqual(actualUser.id, expectedUser.id)
  }

  // other tests ...
}

This is not the best example (because UserManager is just a wrapper around database) but I hope you have got some ideas of how write unit tests

\$\endgroup\$
1
\$\begingroup\$

You should think about WHAT you test.

You just test in your UnitTest the Json encoder. But i think the json encoder is still good tested and you not need to test it again.

You should test business logic (methods/functions) you have written and cover the code with the test

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.