Search code examples
swiftunit-testingpipeline

Any reason why this unit test for DateFormatter in swift is failing when we run the pipeline but works on local?


So the following unit test is working good in our local, but when we run the pipeline the test failed. Any reason why is this happening?

Function to test

public extension DateFormatter {
    func fromYesterday(date: String?, today: String?) -> Bool {
        guard let dateString = date,
              let todayString = today,
              let date = self.date(from: dateString),
              let today = self.date(from: todayString) else {
            return false
        }

        guard let dayBefore = Calendar.current.date(byAdding: .day, value: -1, to: today) else {
            return false
        }

        return self.calendar.isDate(date, inSameDayAs: dayBefore)
    }
}

Test files

struct DateFormatterStubs {
    static var defaultDateFormatter: DateFormatter = {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
        formatter.locale = Locale(identifier: "en_US_POSIX")
        formatter.timeZone = TimeZone(secondsFromGMT: -5)
        return formatter
    }()
}

class DateFormatterExtensionTests: XCTestCase {

    let dateFormatter = DateFormatterStubs.defaultDateFormatter

    func testFromYesterday_todayAsDayBeforeDayThanGivenDate_returnsTrue() {
        var date: String = "2021-01-09T23:59:59-05:00"
        var today: String = "2021-01-10T00:00:00-05:00"

        XCTAssertTrue(dateFormatter.fromYesterday(date: date, today: today))

        date = "2021-01-09T00:00:00-05:00"
        today = "2021-01-10T23:59:59-05:00"

        XCTAssertTrue(dateFormatter.fromYesterday(date: date, today: today))
    }
}

I expect the unit test have some mock data to pass the pipeline run.


Solution

  • Here, you are using the date formatter's calendar to determine if the two dates are in the same day.

    self.calendar.isDate(date, inSameDayAs: dayBefore)
    

    However, you never set dateFormatter.calendar in your tests, so the current system calendar is used. This means that formatter.calendar.timeZone is the system's time zone.

    While 2021-01-09T23:59:59-05:00 is in the previous day of 2021-01-10T00:00:00-05:00 at UTC-5, that isn't necessarily true for other timezones. Your local system might be using a timezone with a -5 offset at that time, but the pipeline server uses a different timezone.

    For the tests to succeed, you can set formatter.calendar.timeZone to -5 hours:

    dateFormatter.calendar.timeZone = TimeZone(secondsFromGMT: -5 * 60 * 60)!
    

    Note that setting formatter.timeZone is unnecessary, since there is already an offset in your date-time string.