如何单元调用NSDate()的测试方法?

时间:2015-03-06 07:00:42

标签: ios unit-testing swift nsdate

我目前正在使用Swift。

我的问题很简单,你如何使用NSDate()作为属性来单元测试在数据库中创建对象的方法?

问题在于我的断言我会像这样创建一个新的NSDate():

let expectedObject = Object(data: NSDate())
XCTAssertEqual(database.objects(), [expectedObject])

并且断言将失败,因为2个NSDates略有不同。

谢谢。

5 个答案:

答案 0 :(得分:0)

一个简单的解决方法是使用以下方法:

  1. 创建一个派生自测试类的模拟类。
  2. 在被测试的类中添加类似“getDate() - > NSDate”的方法     返回“NSDate()” - 或任何预期的值。
  3. 覆盖     mockClass中的getDate()。您还可以在mock中创建变量     class,从getDate()返回。有了这个,你就可以了     从测试中提供你想要的任何日期。
  4. 最后,不要创建您想要测试的类实例, 创造     测试中模拟类的实例。

答案 1 :(得分:0)

正如https://testdriven-ios.com

所指出的那样

一个非常好的方法是在测试用例中覆盖NSDate.date,强制它返回一个已知日期

@implementation NSDate (custom)

+ (instancetype)date{
    NSDateFormatter* formatter = NSDateFormatter.new;
    [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ssZZZ"];
    return [formatter dateFromString:@"2017-12-28 13:00:10+0000"];
}

@end

然后在任何调用NSDate.date的地方,都会返回2017-12-28 13:00:10+0000

@implementation NSDate (custom)

+ (instancetype)date{
    NSDateFormatter* formatter = NSDateFormatter.new;
    [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ssZZZ"];
    return [formatter dateFromString:theDate];
}

@end

您甚至可以使用静态date变量进一步自定义它,然后在测试中对其进行修改

-(void) test_something_out {
 theDate = @"2017-12-28 13:00:10+0000";
 //Test any function that uses nsdate.date
}

答案 2 :(得分:0)

测试使用Date()(或CLLocationManager,ReachabilityManager或其他任何静态方法)的方法的一种好方法是为整个应用程序设置一个可以在测试中模拟的环境。

为此,请创建一个环境类,如下所示:

struct Environment {

    var date: Date = Date()
}

var Env = Environment()

在应用的其余部分中,通过Env.date访问当前日期,而不是调用Date()

在测试中,创建一个像这样的模拟环境:

extension Environment {

    static let mock = Environment(
        date: Date(year: 2019, month: 11, day: 12, hour: 2, minute: 45)
    )
}

在测试设置中,将应用环境替换为模拟环境,如下所示:

override func setUp() {

    super.setUp()

    Env = .mock
}

我建议将其放在所有测试类都将继承的基类中,以便每个测试都将使用模拟环境。

现在,当您运行应用程序时,您将看到当前日期,但是在测试中,该日期始终会回到2019年11月12日02:45,因此您可以验证从该已知日期开始想要的日期。

对于此设置的工作示例,我创建了一个小演示项目here。相关文件是Environment.swift,MockEnvironment.swift,DateExamplesViewController.swift和DateTests.swift。

答案 3 :(得分:0)

如果你能像这样使用Date.now(),实现起来会非常简单和干净

extension Date {
    static var now: (()->Date) = {
        return Date()
    }
}

print(Date.now())
Date.now = { Date().addingTimeInterval(43534543) }
print(Date.now())

答案 4 :(得分:0)

NSDate.date (Objective C)、Date() (Swift)、Date.now() 在其他语言中都存在模拟问题,因为它们应该在不同的对象上给出不同的结果。电话。

因此,如果我将一个对象添加到具有当前日期的数据库,并检查当我从数据库中读取它时它是否具有当前日期,那将不起作用。不是因为数据库或 Date.now() 函数有问题,而是因为您使用它的方式。

模拟 Date.now() 总是返回相同的日期以使您的测试工作从根本上是有缺陷的,因为模拟的 Date.now() 没有按照它应该的方式工作!连续两次调用应该返回不同的日期,而不是同一个!

正确的方法:创建一个日期对象 D,任何你喜欢的方式。添加日期为 D 的对象,将其写入数据库,从数据库中读取,检查对象的日期是否为 D。然后检查数据库文档中关于精度的说明:如果将日期存储为秒,并且您以毫秒为单位存储日期,然后更改对象的定义(“此对象将所有日期四舍五入为整秒”),或者接受写入 + 读取返回日期略有不同的对象,并相应地更改单元测试.

所以你要做的是记录你期望的行为,让单元测试测试预期的行为,失败时你决定单元测试是错误的,或者你的代码是错误的,或者预期的行为应该是不同的。 (单元测试也可能有错误,预期行为的规范也可能有错误)。