2015-10-22 1 views
1

Скажем, у меня есть struct, который соответствует Equatable для моей модели, что-то вроде этого:блок стратегия тестирования для соответствующей Equatable

struct Model: Equatable { 
    var a: Int = 0 
    var b: String = "" 
} 

func ==(lhs: Model, rhs: Model) -> Bool { 
    return lhs.a == rhs.a && lhs.b == rhs.b 
} 

Теперь я пишу несколько модульных тестов для этого. Что-то вроде:

func testModelsAreEqual() { 
    let model1 = Model() 
    let model2 = Model() 
    XCTAssertEqual(model1, model2) 
} 

func testModelsAreNotEqual1() { 
    let model1 = Model() 
    var model2 = Model() 
    model2.b = "hello world" 
    XCTAssertNotEqual(model1, model2) 
} 

func testModelsAreNotEqual2() { 
    let model1 = Model() 
    var model2 = Model() 
    model2.a = 1 
    XCTAssertNotEqual(model1, model2) 
} 

Но как я могу написать тест, который защитит меня от сценария, и другое свойство добавляется Model без добавления в проверке почленно-равенства для == как:

struct Model: Equatable { 
    var a: Int = 0 
    var b: String = "" 
    var c: Double = 0 
} 

func ==(lhs: Model, rhs: Model) -> Bool { 
    return lhs.a == rhs.a && lhs.b == rhs.b 
} 

Где, очевидно, мои тесты все равно пройдут, хотя концептуально мой Equatable не работает. Есть ли стратегия тестирования, которую я могу принять здесь, которая поможет предупредить меня об этой проблеме? Есть ли что-то, что я могу сделать с Swift's Mirror и ограниченным отражением? Возможно Mirror.children.count? Или у кого-то есть лучшее предложение?

ответ

2

После поиска других решений, я решил использовать отражение для подсчета членов, чтобы предупредить меня об изменениях. Вот тест для примера выше:

func testModelStillHas2Members() { 
    XCTAssertEqual(Mirror(reflecting: Model()).children.count, 2, "The member count of Model has changed, please check the `==` implementation to ensure all members are accounted for.") 
} 
+0

Вы нашли лучшее, менее косвенное решение для этой проблемы? Очень просто сделать неправильный протокол для принятого типа неправильным, и его, вероятно, очень трудно заметить без надлежащих модульных тестов. – bartzy

+0

К сожалению, я этого не делал. И, судя по некоторым другим дискуссиям, которые я видел в Интернете, нет никаких лучших идей. –

0

Это мое мнение:

func testModel3() { 
    let model1 = Model() 
    var model2 = Model() 
    model2.c = 1 
    model2.p.name = "Jack" 

    let mirror1 = Mirror(reflecting: model1) 
    let mirror2 = Mirror(reflecting: model2) 

    let prop1 = mirror1.children.reduce([String: NSObject]()) { 
     (var dict, e) in 
     dict[e.label!] = e.value as? NSObject 
     return dict 
    } 
    let prop2 = mirror2.children.reduce([String: NSObject]()) { 
     (var dict, e) in 
     dict[e.label!] = e.value as? NSObject 
     return dict 
    } 

    if model1 == model2 { 
     XCTAssertEqual(prop1, prop2, "Not really equal") 
    } else { 
     XCTAssertNotEqual(prop1, prop2, "Not really diffrent") 
    } 
} 

Он строит 2 словаря с именами & значения всех свойств в model1 и model2, то утверждающие, если эти 2 словаря равны.

Большое предупреждение: Я не проверил это полностью. Он работал для ограниченного числа случаев, которые я бросил на него. Возможно, вам придется импровизировать.

+0

Я не думаю, что это будет работать, если значения в зеркале не являются дециентами 'NSObject', например. настраиваемые структуры и перечисления. –

+0

Я также не уверен, что это получает то, что я хочу, потому что я не думаю, что он поймает, когда вы добавите дополнительные свойства, но не добавили их члену мудрым, равным реализации '==' –

+0

@JackLawrence вы правы , Отражение в Свифт - это ограниченное дело. Он не работает, когда объект не конвертируется в 'NSObject'. Я думаю о том, как обращаться с этими случаями. –

Смежные вопросы