测试一个在私有变量中保留其状态的类

时间:2018-01-11 13:28:15

标签: swift unit-testing

我正在为我的班级编写单元测试。这个类在一些private变量中保留其状态(我不想公开公开)。所以场景是:

  • 如果我调用一个方法,它第一次将该状态保存在private属性中并调用一个带有一些结果的委托方法。
  • 当我第二次调用相同的方法时,输出将根据之前的输入而有所不同。

我希望涵盖测试中的所有案例。

  • 一种简单的方法是将我的私有属性更改为public,以便我可以在单元测试中模拟以前的输入。
  • 另一种方法是在同一个测试中使用不同的输入调用相同的方法两次。第一次通话将保持状态,下次通话将是实际测试。

但这两种方式对我来说都很尴尬,我不确定最好的方式。 为这门课程编写单元测试的最佳方法是什么?

protocol ZoneUpdateDetectorOutput: class {
    func updateZoneState(_ state: ZoneState)
}

class ZoneUpdateDetector {
    var zoneChangeTimer: TimerProtocol?
    weak var delegate: ZoneUpdateDetectorOutput?

    private var previousZoneState: ZoneState?
    private var expectedZoneState: ZoneState?

    private func updateZoneState() {
        // If `expectedZoneState` is not equal to `previousZoneState` then `delegate` will be called
        // Otherwise it will just skip
        if expectedZoneState != previousZoneState {
            delegate?.updateZoneState(expectedZoneState!)
            previousZoneState = expectedZoneState
        }
    }

    private func runNotifyZoneStateTimer() {
        guard zoneChangeTimer?.isValid() == false else {
            return
        }
        zoneChangeTimer?.start(timeInterval: 5,
                               onFire: { [weak self] in
                                guard let strongSelf = self else {
                                    return
                                }
                                // On timer fire, it will try to update the state
                                strongSelf.updateZoneState()
        })
    }

    // When zone changes, this method is invoked
    // I basically want to test this method
    func zoneStateChanged(_ state: ZoneState) {
        expectedZoneState = state
        if state != .inZone {
            runNotifyZoneStateTimer()
        } else {
            zoneChangeTimer?.stop()
        }
    }
}

2 个答案:

答案 0 :(得分:2)

你永远不应该测试内部状态;您应该只测试外部(公开)可见行为。这样,您可以在不违反任何合同的情况下更改班级的实施细节,从而不会破坏任何测试。

所以第二个选项是首选。

答案 1 :(得分:0)

在与一些专家进行研究和讨论之后,我想出了一个解决方案,如果我们想测试一个保留状态的类,那么保留状态的功能应该在一个单独的类下。这与将变量设置为私有的目的相同。因此,ZoneUpdateDetector应该具有依赖关系,例如:ZoneUpdateStatePreserver并且它应该保留以前在ZoneUpdateDetector内的状态