代码之家  ›  专栏  ›  技术社区  ›  Cheok Yan Cheng

如何在单元测试期间模拟默认时区?

  •  0
  • Cheok Yan Cheng  · 技术社区  · 3 年前

    在单元测试期间,我想临时模拟特定国家的默认时区。这就是我目前所做的,通过使用全局变量。

    应用程序代码

    import Foundation
    
    var _TIME_ZONE_FOR_UNIT_TEST: TimeZone? = nil
    
    extension TimeZone {
        static func current() -> TimeZone {
            if let _TIME_ZONE_FOR_UNIT_TEST = _TIME_ZONE_FOR_UNIT_TEST {
                return _TIME_ZONE_FOR_UNIT_TEST
            } else {
                return TimeZone.current
            }
        }
    }
    

    单元测试

    func testToDayResolutionInCuba() throws {
        let cubaTimeZone = TimeZone(identifier: "America/Havana")!
        
        _TIME_ZONE_FOR_UNIT_TEST = cubaTimeZone
        defer {
            _TIME_ZONE_FOR_UNIT_TEST = nil
        }
        
        ...
        
        // ReminderUtils.toDayResolution is depending on TimeZone.current()
        let timestampWithoutTime = ReminderUtils.toDayResolution(timeMillis)
    

    虽然有效,但我不喜欢这样的方式

    1. 使用全局变量
    2. 额外的运行时间成本 if 检查

    对于我来说,有没有更好的方法来针对特定时区执行单元测试?

    0 回复  |  直到 3 年前
        1
  •  1
  •   Cristik    3 年前

    TimeZone 是对Objective-C的直接包装 NSTimeZone TimeZone.current 对应于 NSTimeZone.systemTimeZone .

    因此,您可以模拟/存根 时间地带。系统时区 任何嘲弄的框架。这将帮助你摆脱那些讨厌的事情 if 从你的代码库。

        2
  •  1
  •   Cheok Yan Cheng    3 年前

    模仿可以通过变异来完成 NSTimeZone.default

    // Cuba will advance its clock by 1 hour, during 2021-03-14 00:00 am. This means during 2021-03-13 23:59 pm, after
    // next 1 second, the time will be 2021-03-14 01:00 am.
    func testToDayResolutionInCuba() throws {
        let cubaTimeZone = TimeZone(identifier: "America/Havana")!
        let oldDefault = NSTimeZone.default
        NSTimeZone.default = cubaTimeZone
        defer {
            NSTimeZone.default = oldDefault
        }
        
        var dateComponents = DateComponents()
        dateComponents.year = 2021
        dateComponents.month = 3
        dateComponents.day = 14
        dateComponents.hour = 0
        dateComponents.minute = 0
        dateComponents.second = 0
        
        let calendar = Calendar.current
        let date = calendar.date(from: dateComponents)!
        
        let timeMillis = date.timeMillis
        
        let timestampWithoutTime = ReminderUtils.toDayResolution(timeMillis)
        
        let dateWithoutTime = Date(timeIntervalSince1970: Double(timestampWithoutTime/1000))
        let result = calendar.dateComponents(in: cubaTimeZone, from: dateWithoutTime)
        
        XCTAssertEqual(2021, result.year)
        XCTAssertEqual(3, result.month)
        XCTAssertEqual(14, result.day)
        XCTAssertEqual(1, result.hour)
        XCTAssertEqual(0, result.minute)
        XCTAssertEqual(0, result.second)
    }