Как протестировать требуемый init(coder:)?

В моем пользовательском классе WLNetworkClient мне пришлось реализовать такой метод:

required init(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

Мне не нужно это использовать, но я хотел бы проверить это, чтобы обеспечить 100% покрытие кода. Вы знаете, как этого добиться?

Я пробовал следующим образом без успеха:

let nc = WLNetworkClient(coder: NSCoder())
XCTAssertNotNil(nc)

person Bartłomiej Semańczyk    schedule 10.09.2015    source источник


Ответы (5)


Производственный код:

required init?(coder: NSCoder) {
    return nil
}

Тест:

func testInitWithCoder() {
    let archiverData = NSMutableData()
    let archiver = NSKeyedArchiver(forWritingWithMutableData: archiverData)
    let someView = SomeView(coder: archiver)
    XCTAssertNil(someView)
}

Поскольку требуемый инициализатор возвращает nil и не использует кодировщик, приведенный выше код можно упростить до:

func testInitWithCoder() {
    let someView = SomeView(coder: NSCoder())
    XCTAssertNil(someView)
}
person Rudolf Adamkovič    schedule 24.08.2016
comment
Это не работает для меня в немного другой ситуации. Я вызываю super.init(coder: aDecoder) в качестве второй строки, и он перестает работать на этой строке. Никакой сбой просто не заканчивает тест. - person Jeremiah; 31.01.2018
comment
У меня не получается (Xcode 9.3, Swift 4.1): test failure: testInitWithCoder() failed: failed: caught "NSInvalidArgumentException", "*** -decodeObjectForKey: only defined for abstract class. Define -[NSKeyedArchiver decodeObjectForKey:]!" - person Oliver Pearmain; 10.04.2018
comment
@Oliver, когда я получил эту ошибку, это произошло потому, что я скармливал своему инициализатору выделенный архиватор вместо выделенного DEarchiver ... Я должен был создать новый NSKeyedUnarchiver с archiverData в качестве параметра инициализации. - person Liz; 05.06.2018
comment
Инициализатор NSKeyedArchiver(forWritingWith:) устарел в iOS12. Если вы получаете это предупреждение, вы можете заменить строку на let archiver = NSKeyedArchiver(requiringSecureCoding: true) - person Martin; 19.11.2018
comment
Теперь это не сработает, сбой с ошибкой caught "NSInvalidArgumentException", "*** -containsValueForKey: cannot be sent to an abstract object of class NSCoder: Create a concrete instance!" - person Saif; 06.02.2020

Вот ответ, который должен вам помочь:

let cd = NSKeyedUnarchiver(forReadingWithData: NSMutableData())
let c = CustomTextField(coder:cd)
person Patrick    schedule 22.12.2015
comment
К сожалению, это все еще не работает: *** -[NSKeyedUnarchiver initForReadingWithData:]: data is empty; did you forget to send -finishEncoding to the NSKeyedArchiver? - person Bartłomiej Semańczyk; 22.12.2015

Ответ от Рудольфа Адамковича, который все еще работает со Swift 4:

required init?(coder aDecoder: NSCoder) {
    return nil
}

func testInitWithCoder() {
    // 1. Arrange
    let archiver = NSKeyedArchiver(forWritingWith: NSMutableData())

    // 2. Action
    let viewController = ViewController(coder: archiver)

    // 3. Assert
    XCTAssertNil(viewController)
}
person sundance    schedule 24.03.2018
comment
XCTAssertNil? XCTAssertNotNil обязательно. - person Oliver Pearmain; 10.04.2018
comment
@Oliver Pearmain Учитывая, что текущая реализация возвращает nil, AssertNil является правильным тестом (даже если у большинства из нас, вероятно, будет NotNil) - person Liz; 04.06.2018
comment
NSKeyedArchiver (forWritingWith: NSMutableData()) устарел. - person Satyam; 03.01.2020

Я объединил ответ Рудольфа с предложением Лиз и закончил со следующим решением:

let viewController = SomeTableViewController(
    presenter: SomePresenterMock(),
    coder: NSKeyedUnarchiver(forReadingWith: Data())) 

XCTAssert(viewController?.tableView.numberOfSections == 1)

Ключевым моментом здесь является использование NSKeyedUnarchiver(forReadingWith: Data()) в качестве фиктивного кодера, иначе тест вылетит с NSInvalidArgumentException.

person piperamirez    schedule 07.06.2018

Я использую улучшенный ответ Адамковича Рудольфа:

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

func test_initWithCoder() {
    let object = SomeView()
    let data = NSKeyedArchiver.archivedData(withRootObject: object)
    let coder = NSKeyedUnarchiver(forReadingWith: data)
    let sut = SomeView(coder: coder)
    XCTAssertNotNil(sut)
}
person ChikabuZ    schedule 12.02.2021