高效可测试的结构



我正试图找到一种方法来定义一个结构,使其内部持有非指针类型,并保持易于测试的能力。我不想使用协议,因为不是有实际的数据内部的结构指针将被持有。如果我决定使用ptr支持类型,我将以如下方式实现一段示例代码

protocol TimeGetable {
var currentTime: Date { get }
}
struct Chronometer {
private let timeGetter: TimeGetable
private var startTime: Date

init(timeGetter: TimeGetable) {
self.timeGetter = timeGetter
startTime = timeGetter.currentTime
}
mutating func reset() {
startTime = timeGetter.currentTime
}

func elapsedTime() -> TimeInterval {
timeGetter.currentTime.timeIntervalSince(startTime)
}
}
struct RealGetter: TimeGetable {
var currentTime: Date { Date() }
}
struct FakeGetter: TimeGetable {
var currentTime: Date {
// Do some magic here to ease testing
// Return the same value each time as an example
return Date.distantPast
}
}

在这种方法中,无论实现TimeGetable的类/结构有多大,Chronometer的大小都保持不变。

MemoryLayout<Chronometer>.size // 48 bytes

如果我决定不测试我的代码,我会这样定义Chronometer

struct Chronometer {
private var startTime: Date

init(timeGetter: TimeGetable) {
startTime = Date()
}
mutating func reset() {
startTime = Date()
}

func elapsedTime() -> TimeInterval {
Date().currentTime.timeIntervalSince(startTime)
}
}

在这种情况下,如果Date类型大小上升Chronometer也上升,因为它持有非引用类型。这有利于提高性能并避免缓存丢失。我唯一想到的办法是做如下的事情


#if TESTS
public typealias DateType = DateMock
#else
public typealias DateType = Date
#endif
struct Chronometer {
private var startTime: DateType

init(timeGetter: TimeGetable) {
startTime = DateType()
}
mutating func reset() {
startTime = DateType()
}

func elapsedTime() -> TimeInterval {
DateType().currentTime.timeIntervalSince(startTime)
}
}

我将在带有测试的目标中定义TESTS标志,而在生产代码中不定义任何标记。这似乎是一个相当丑陋的解决方案。最重要的是,这意味着在我的生产代码中只提到用于测试目的的类/结构。有没有更好的办法?

也许你可以考虑这样做一个结构体:

struct Chronometer {
private let timeGetter: () -> Date
private var startTime: Date

init(timeGetter: @escaping () -> Date = Date.init) {
self.timeGetter = timeGetter
startTime = timeGetter()
}
mutating func reset() {
startTime = timeGetter()
}

func elapsedTime() -> TimeInterval {
timeGetter().timeIntervalSince(startTime)
}
}

mock/stub很简单。然后你可以在struct的init中调用这些函数来创建你关心的实际日期。在测试用例中,它将是某个固定的日期函数,在实际中,是正常的date。Init返回当前日期/时间

相关内容

  • 没有找到相关文章

最新更新