Пробное расширение UIView "ApiProtocol" в тесте - swift4 - PullRequest
0 голосов
/ 25 мая 2018

Учитывая протокол и расширение, которое «внедряется» в MyUIView.Функцию stubMePlease() можно вызвать, и она возвращает "привет мир", как и ожидалось.

При выполнении юнит-теста stubMePlease() нужно проверять в 3 разных тестах.

Какой подход лучше?

Протокол и расширение

protocol ApiProtocol {
    func stubMePlease() -> String
}

extension ApiProtocol {
    func stubMePlease() -> String {
        return "hello world"
    }
}

UIView "внедрить / расширить" ApiProtocol

class MyUIView: UIView, ApiProtocol {

    override init(frame: CGRect) {
        super.init(frame: frame)
        foo()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    public func foo() -> String {
        return self.stubMePlease() // returns "hello world"
    }
}

Тестовый класс

import XCTest
class test: XCTestCase {  
    var myview: MyUIView!

    override func setUp() {
        super.setUp()
        myview = MyUIView()
    }

    func testA() {
        let kom = myview.foo()
        XCTAssertEqual(kom, "hello") // how do I mock this with "hello"
    }

    func testB() {
        let kom = myview.foo()
        XCTAssertEqual(kom, "weekend") // how do I mock this with "weekend"
    }

    func testC() {
        let kom = myview.foo()
        XCTAssertEqual(kom, "swift") // how do I mock this with "swift"
    }
}

Спасибо

1 Ответ

0 голосов
/ 25 мая 2018

Вы не должны использовать «расширение» для реализации функций протокола, вы должны использовать его для расширения вашего протокола, то есть добавления новых функций.Обычно вы расширяете свой собственный протокол с некоторыми перегрузками вспомогательных методов и реализуете их в терминах методов в протоколе, чтобы каждый класс, реализующий тот же протокол, мог избежать их реализации (в то время как клиенты получают выгоду от перегрузок).

Сначалавсего, что вам нужно, чтобы иметь фактические реализации вашего протокола:

class ApiProtocolForTests: ApiProtocol {
    func stubMePlease() -> String {
        return "fake hello world in test"
    }
}

class ApiProtocolForRealz: ApiProtocol {
    func stubMePlease() -> String {
        return "hello world in real life"
    }
}

Затем в MyUIView вместо наследования / реализации ApiProtocol, который концептуально не имеет смысла, вы должны передать его в конструкторы инициализации, например:

class MyUIView: UIView {
    let api: ApiProtocol

    override init(frame: CGRect, api: ApiProtocol) {
        super.init(frame: frame)
        self.api = api
        foo()
    }
    ...

В тестах вы создали бы MyUIView, предоставив ему версию протокола ApiProtocolForTests: myview = MyUIView(frame: frame, api: ApiProtocolForTests())

Это также известно как "внедрение" зависимости"ApiProtocol".

...