iOS自动化测试 - 数据存储之FeedStoreSpy

2,003 阅读3分钟

我们将学习如何使用 Swift 创建一个名为 FeedStoreSpy 的类,该类用于模拟一个数据存储(FeedStore)的行为。我们将详细讲解每个方法的作用以及如何使用它们来测试我们的代码。

1. 简介

FeedStoreSpy 是一个遵循了 FeedStore 协议的类。它的主要目的是记录所有调用的信息,以便后续进行测试。我们将使用它来模拟对存储数据的各种操作,如插入、删除和检索。

2. 类的结构

让我们先来看一下 FeedStoreSpy 类的结构:

class FeedStoreSpy: FeedStore {
    enum ReceivedMessage: Equatable {
        case deleteCachedArticle
        case insert([LocalArticle], Date)
        case retrieve
    }
    
    private(set) var receivedMessages = [ReceivedMessage]()
    
    private var deletionCompletions = [DeletionCompletion]()
    private var insertionCompletions = [InsertionCompletion]()
    private var retrievalCompletions = [RetrievalCompletion]()
    
    // Methods implementation...
}

3. 方法解释

现在,让我们逐个解释每个方法的作用和实现细节。

3.1 deleteCachedFeed(completion:)
func deleteCachedFeed(completion: @escaping DeletionCompletion) {
    deletionCompletions.append(completion)
    receivedMessages.append(.deleteCachedFeed)
}

此方法用于模拟删除缓存文章的行为。它接受一个 completion 闭包作为参数,该闭包在操作完成时被调用。在此方法中,我们将传入的 completion 闭包添加到 deletionCompletions 数组中,并将 .deleteCachedFeed 添加到 receivedMessages 数组中以记录该操作。

3.2 completeDeletion(with:at:)completeDeletionSuccessfully(at:)
func completeDeletion(with error: Error, at index: Int = 0) {
    deletionCompletions[index](.failure(error))
}

func completeDeletionSuccessfully(at index: Int = 0) {
    deletionCompletions[index](.success(()))
}

这两个方法用于模拟删除操作的完成状态。completeDeletion(with:at:) 方法用于模拟删除操作失败的情况,它会调用对应索引处的 deletionCompletions 中的闭包,并传入一个错误。而 completeDeletionSuccessfully(at:) 方法用于模拟删除成功的情况,它会调用对应索引处的 deletionCompletions 中的闭包,并传入一个空的成功结果。

3.3 insert(_:timestamp:completion:)
func insert(_ articles: [LocalArticle], timestamp: Date, completion: @escaping InsertionCompletion) {
    insertionCompletions.append(completion)
    receivedMessages.append(.insert(articles, timestamp))
}

此方法用于模拟插入文章到缓存的操作。它接受一个文章数组、时间戳和一个 completion 闭包作为参数。在此方法中,我们将传入的 completion 闭包添加到 insertionCompletions 数组中,并将包含文章数组和时间戳信息的 .insert 枚举添加到 receivedMessages 数组中。

3.4 completeInsertion(with:at:)completeInsertionSuccessfully(at:)
func completeInsertion(with error: Error, at index: Int = 0) {
    insertionCompletions[index](.failure(error))
}

func completeInsertionSuccessfully(at index: Int = 0) {
    insertionCompletions[index](.success(()))
}

这两个方法用于模拟插入操作的完成状态,与删除操作类似。

3.5 retrieve(completion:)
func retrieve(completion: @escaping RetrievalCompletion) {
    retrievalCompletions.append(completion)
    receivedMessages.append(.retrieve)
}

此方法用于模拟从缓存中检索文章的操作。它接受一个 completion 闭包作为参数,在检索完成后调用。在此方法中,我们将传入的 completion 闭包添加到 retrievalCompletions 数组中,并将 .retrieve 添加到 receivedMessages 数组中。

3.6 completeRetrieval(with:error:at:), completeRetrievalWithEmptyCache(at:)completeRetrieval(with:timestamp:at:)

这些方法用于模拟检索操作的完成状态,与删除和插入操作类似,但有一些细微差别。这些方法分别模拟检索失败、检索到空缓存和成功检索到文章的情况。

4. 总结

通过实现 FeedStoreSpy 类,我们可以模拟对存储数据的各种操作,并记录这些操作的调用情况,以便后续进行测试。这种模式在编写单元测试时非常有用,因为我们可以验证代码是否按预期执行了存储数据的操作。

代码链接

GitHub 仓库