【问题标题】:Test fails when asserting dates断言日期时测试失败
【发布时间】:2017-04-10 01:23:00
【问题描述】:

我正在尝试验证我存储的两个项目是否相同。但是,在测试时检查 Date 属性时出现错误。

注意:我的 Item 类实现了Equatable 协议。

这是我的设置方法:

class InputViewControllerTests: XCTestCase {

    var sut: InputViewController!
    var placemark: MockPlacemark!

    override func setUp() {
        super.setUp()
        let storyboard = UIStoryboard(name: "Main",
                                      bundle: nil)
        sut = storyboard
            .instantiateViewController(
                withIdentifier: "InputViewController")
            as! InputViewController
        _ = sut.view
    }
}

这是我的测试类的扩展:

extension InputViewControllerTests {
    class MockGeocoder: CLGeocoder {
        var completionHandler: CLGeocodeCompletionHandler?
        override func geocodeAddressString(
            _ addressString: String,
            completionHandler: @escaping CLGeocodeCompletionHandler) {
            self.completionHandler = completionHandler
        }
    }

    class MockPlacemark : CLPlacemark {
        var mockCoordinate: CLLocationCoordinate2D?
        override var location: CLLocation? {
            guard let coordinate = mockCoordinate else
            { return CLLocation() }
            return CLLocation(latitude: coordinate.latitude,
                              longitude: coordinate.longitude)
        }
    }
}

这是我的测试:

func test_Save_UsesGeocoderToGetCoordinateFromAddress() {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "MM/dd/yyyy"
        let timestamp = 1456095600.0
        let date = Date(timeIntervalSince1970: timestamp)
        sut.titleTextField.text = "Foo"
        sut.dateTextField.text = dateFormatter.string(from: date)
        sut.locationTextField.text = "Bar"
        sut.addressTextField.text = "Infinite Loop 1, Cupertino"
        sut.descriptionTextField.text = "Baz"
        let mockGeocoder = MockGeocoder()
        sut.geocoder = mockGeocoder
        sut.itemManager = ItemManager()
        sut.save()
        placemark = MockPlacemark()
        let coordinate = CLLocationCoordinate2DMake(37.3316851,
                                                    -122.0300674)
        placemark.mockCoordinate = coordinate
        mockGeocoder.completionHandler?([placemark], nil)
        let item = sut.itemManager?.item(at: 0)
        let testItem = ToDoItem(title: "Foo",
                                itemDescription: "Baz",
                                timestamp: timestamp,
                                location: Location(name: "Bar",
                                                   coordinate: coordinate))
        XCTAssertEqual(item, testItem)
    }

这是save()方法的实现:

class InputViewController: UIViewController {
    // ...
    @IBAction func save() {
        guard let titleString = titleTextField.text,
            titleString.characters.count > 0 else { return }
        let date: Date?
        if let dateText = self.dateTextField.text,
            dateText.characters.count > 0 {
            date = dateFormatter.date(from: dateText)
        } else {
            date = nil
        }
        let descriptionString = descriptionTextField.text
        if let locationName = locationTextField.text,
            locationName.characters.count > 0 {
            if let address = addressTextField.text,
                address.characters.count > 0 {
                geocoder.geocodeAddressString(address) {
                    [unowned self] (placeMarks, error) -> Void in
                    let placeMark = placeMarks?.first
                    let item = ToDoItem(
                        title: titleString,
                        itemDescription: descriptionString,
                        timestamp: date?.timeIntervalSince1970,
                        location: Location(
                            name: locationName,
                            coordinate: placeMark?.location?.coordinate))
                    self.itemManager?.add(item)
                }
            }
        }
    }
}

我无法弄清楚这有什么问题。我得到的错误是:

test_Save_UsesGeocoderToGetCoordinateFromAddress()] 失败:XCTAssertEqual 失败:("Optional(ToDo.ToDoItem(title: "Foo", itemDescription: Optional("Baz"), timestamp: Optional(1456030800.0)), location: Optional(ToDo.Location(名称:“酒吧”,坐标:可选(__C.CLLocationCoordinate2D(纬度:37.331685100000001,经度:-122.03006739999999))))))”)不等于(“可选(ToDo.ToDoItem(标题:“Foo”,itemDescription:可选(“Baz”),时间戳:可选(1456095600.0),位置:可选(ToDo.Location(名称:“Bar”,坐标:可选(__C.CLLocationCoordinate2D(纬度:37.331685100000001,经度:-122.03006739999999)))))) ") -

可以清楚地看到,问题是两者的时间戳不一样,我不知道它为什么会改变。

编辑:正如@ganzogo 发现的那样,这两个项目之间也有正好 18 小时的差异。我住在厄瓜多尔,这是 GTM-5。也许这可能是找出问题的线索。

【问题讨论】:

  • 使用XCTAssertEqual,您可以检查对象地址的相等性。但是你的itemtestItem不一样。
  • @ArtemNovichkov,请注意,正如我所说,一切都是一样的,但 tiemestamp 属性,我不知道为什么,因为我使用 1456095600.0 来创建两者。实际上,请注意 item 是 1456030800.0,而 testItem 是 1456095600.0。我不知道为什么 item 的值会发生变化。
  • 顺便说一句@ArtemNovichkov,我认为只要一个类实现了Equatable 协议,你就可以检查相等性,而我的Item 类可以。
  • 时差正好是 18 小时,所以我怀疑是时区问题。
  • 您首先需要确定testItemitem 显示的时间是否正确,然后您需要通过手动穿越时区来调整另一个。单元测试将在模拟器或设备上运行,DateFormatter 等类将默认使用设备的时区,因此您需要覆盖它。

标签: ios swift unit-testing testing xctest


【解决方案1】:

在你的线路之后:

let dateFormatter = DateFormatter()

试试这个:

dateFormatter.timeZone = TimeZone(secondsFromGMT: 64800)

如果这不起作用,请尝试:

dateFormatter.timeZone = TimeZone(secondsFromGMT: -64800)

:-)

但是,如果您只是破解单元测试直到通过,您就有点违背了单元测试的目的。您确实需要了解 testItemitem 目前是否表现出正确的行为,这取决于您的应用程序。

【讨论】:

  • 我都试过了,但都没有。当我尝试第一个时,仍然有六个小时的差异。我已经尝试增加了 6 小时,但现在我又相差了 18 小时。
  • 我什至尝试过更改位置,但还是没有解决。
【解决方案2】:

在函数中 test_Save_UsesGeocoderToGetCoordinateFromAddress() 时间戳转换为 sut.dateTextField.text,然后 在 sut.save() sut.dateTextField.text 转换为时间戳,分秒去掉

【讨论】:

    猜你喜欢
    • 2021-10-25
    • 1970-01-01
    • 2021-12-31
    • 2020-10-08
    • 1970-01-01
    • 2017-10-31
    • 1970-01-01
    • 1970-01-01
    • 2020-01-29
    相关资源
    最近更新 更多