如何对静态属性进行单元测试?

3
我有一个名为ConferenceNumberDirectory的目录,其中包含一个build函数,该函数解析JSON文件以创建ConferenceNumber对象的静态数组。我想对此函数进行单元测试。
我使用较小的JSON文件创建了一个单元测试来测试它,但我的测试失败了,因为测试值仅被附加到实际值上。 我的真实值共有56个条目,用于ConferenceNumberDirectory.att数组,但当我运行我的测试时,这些值仍然存在,我的测试值(13个条目)被附加到原始数组中。如何在不污染测试数据的情况下测试我的静态属性?在之前的提交中,我的单元测试ConferenceNumberDirectory.att属性和实际属性是分开的实体,我不知道这里发生了什么(自从这次提交以来,我没有更改过我的测试类)。
class ConferenceNumberDirectory {

static var countryNumbers = [Any]()
static var att = [ConferenceNumber]()
static var arkadin = [ConferenceNumber]()
static var webex = [ConferenceNumber]()
static var zoom = [ConferenceNumber]()

   static func build(from rootJSONArray: [Any]?) {

do {
        guard let rootJSONArray = rootJSONArray else {
            throw SerializationError.missing("JSON Root")
        }

        for entry in rootJSONArray {
            guard let dictionary = entry as? [String: Any] else {
                throw SerializationError.missing("JSON Root")
            }
            guard let isoCode = dictionary["ISO Code"] as? String else {
                throw SerializationError.missing("isoCode")
            }
            guard let country = dictionary["Country"] as? String else {
                throw SerializationError.missing("country")
            }

            if let attTollNumbers = try self.extractNumbers(from: dictionary, forKey: "AT&T toll") {
                ConferenceNumberDirectory.att.append(contentsOf: attTollNumbers.map{ConferenceNumber(ISO: isoCode, country: country, number: $0, provider: ConferenceProvider.att, toll: true) })
            }
            print(ConferenceNumberDirectory.att.count)
            if let attTollFreeNumbers = try self.extractNumbers(from: dictionary, forKey: "AT&T toll-free") {
                ConferenceNumberDirectory.att.append(contentsOf: attTollFreeNumbers.map{ConferenceNumber(ISO: isoCode, country: country, number: $0, provider: ConferenceProvider.att, toll: false)})
            }
            if let arkadinTollNumbers = try self.extractNumbers(from: dictionary, forKey: "Arkadin toll") {
                ConferenceNumberDirectory.arkadin.append(contentsOf: arkadinTollNumbers.map{ConferenceNumber(ISO: isoCode, country: country, number: $0, provider: ConferenceProvider.arkadin, toll: true) })
            }
            if let arkadinTollFreeNumbers = try self.extractNumbers(from: dictionary, forKey: "Arkadin toll-free") {
                ConferenceNumberDirectory.arkadin.append(contentsOf: arkadinTollFreeNumbers.map{ConferenceNumber(ISO: isoCode, country: country, number: $0, provider: ConferenceProvider.arkadin, toll: false) })
            }
            if let webexTollNumbers = try self.extractNumbers(from: dictionary, forKey: "Webex toll") {
                ConferenceNumberDirectory.webex.append(contentsOf: webexTollNumbers.map{ConferenceNumber(ISO: isoCode, country: country, number: $0, provider: ConferenceProvider.webex, toll: true) })
            }
            if let webexTollFreeNumbers = try self.extractNumbers(from: dictionary, forKey: "Webex toll-free") {
                ConferenceNumberDirectory.webex.append(contentsOf: webexTollFreeNumbers.map{ConferenceNumber(ISO: isoCode, country: country, number: $0, provider: ConferenceProvider.webex, toll: false) })
            }
            if let zoomTollNumbers = try self.extractNumbers(from: dictionary, forKey: "Zoom toll") {
                ConferenceNumberDirectory.zoom.append(contentsOf: zoomTollNumbers.map{ConferenceNumber(ISO: isoCode, country: country, number: $0, provider: ConferenceProvider.zoom, toll: true) })
            }
        }
    }
    catch let error {
        print(error)
    }

}
1个回答

1
由于您的属性是“静态”的,它们在代码执行期间一直存在 - 不需要实际的类实例就可以使它们保留在内存中。这就是为什么应该谨慎使用“静态”属性的原因。您可以在Swift文档“类型属性”中了解更多关于“静态”属性的内容。
至于您手头的问题: 您应该利用测试类中的tearDown()方法,并将这些属性恢复到它们的空状态。 tearDown()XCTestCase类中的一个方法,在每个测试用例后运行 - 您可以重写它以为您的测试提供自定义清理。以下是一个简单的例子:
override func tearDown() {
    ConferenceNumberDirectory.att = []()
    super.tearDown()
}

编辑:
为了设置测试环境,您可以覆盖类中的一个相似方法:

override func setUp() {
    super.setUp()
    ConferenceNumberDirectory.att = []()
}

每个测试用例运行之前都会运行此方法。我强烈建议阅读XCTest文档


棘手的问题是这个方法在我的AppDelegate的application.(didFinishLaunchingWithOptions:)函数中被调用,因此真实数据是在测试数据之前创建的。 - Declan McKenna
啊,我明白了。在理想的世界中,这个应用程序启动代码不应该包含在测试中,但我们并不生活在理想的世界。无论如何 - 有一个类似的方法可以重写,以准备你的类进行测试。请参见我上面的编辑。 - Losiowaty
如果我们正在使用私有静态变量呢? :( - Idrees Ashraf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接