Xcode 单元测试 - 添加一个用于所有测试类的通用函数

Posted

技术标签:

【中文标题】Xcode 单元测试 - 添加一个用于所有测试类的通用函数【英文标题】:Xcode Unit Testing - Add a common function to be used across all test classes 【发布时间】:2018-08-13 12:45:49 【问题描述】:

我已经使用 Swift 为我的项目实施了单元测试。在测试用例中,我正在读取来自 CSV 文件的输入值并对其进行验证。目前,每当我创建新的测试用例类时,需要将读取 CSV 文件并解析它的所有函数复制并粘贴到新的测试类中。有没有办法使用这些函数在一个地方读取 CSV 文件,以便所有测试类都可以使用它们?我想重用的代码是:

func csv(data: String) -> [[String]] 
    var result: [[String]] = []
    let rows = data.components(separatedBy: "\n")
    for row in rows 
        let columns = row.components(separatedBy: ",")
        result.append(columns)
    
    return result


func cleanRows(file:String)->String
    var cleanFile = file
    cleanFile = cleanFile.replacingOccurrences(of: "\r", with: "\n")
    cleanFile = cleanFile.replacingOccurrences(of: "\n\n", with: "\n")
    return cleanFile


func readDataFromCSV(fileName:String, fileType: String)-> String!
    let bundle = Bundle(for: type(of: self))
    let path = bundle.path(forResource: fileName, ofType: fileType)!

    do 
        let contents = try String(contentsOfFile: path, encoding: .utf8)
        return contents
     catch 
        print("File Read Error for file \(path)")
        return nil
    

【问题讨论】:

你可以创建一个静态函数并在任何地方使用它,你试过这个流程吗? 不,我会试试的。我应该将静态函数保留在任何一个测试用例文件中吗? 我喜欢使用实用程序和扩展。您应该通过测试覆盖这些方法,然后您可以在任何地方重复使用它们。 让 bundle = Bundle(for: type(of: self)).创建静态函数时如何处理? 像任何其他测试一样。对于最简单的方法,使用规则:给定 -> 当 -> 然后。更多测试签到详情:https://www.raywenderlich.com/709-ios-unit-testing-and-ui-testing-tutorial 【参考方案1】:

您可以使用 Helper 文件来处理此问题。您可以使用静态函数和扩展来完成此操作。

首先,向您的测试项目添加一个新的 swift 文件,最好命名为描述性的,在这种情况下CSVTestUtilityCSVTestHelper 是合理的。

接下来我们要创建一个包含这些方法的结构体。

struct CSVTestUtility 
    static func csv(data: String) -> [[String]] 
        var result: [[String]] = []
        let rows = data.components(separatedBy: "\n")
        for row in rows 
            let columns = row.components(separatedBy: ",")
            result.append(columns)
        
        return result
    

    static func cleanRows(file:String)->String
        var cleanFile = file
        cleanFile = cleanFile.replacingOccurrences(of: "\r", with: "\n")
        cleanFile = cleanFile.replacingOccurrences(of: "\n\n", with: "\n")
        return cleanFile
    

    static func readDataFromCSV(fileName:String, fileType: String)-> String!
        let bundle = Bundle(for: type(of: self) as! AnyClass)
        let path = bundle.path(forResource: fileName, ofType: fileType)!

        do 
            let contents = try String(contentsOfFile: path, encoding: .utf8)
            return contents
         catch 
            print("File Read Error for file \(path)")
            return nil
        
    

此时我们要确保将文件添加到单元测试项目中,因此请确保在文件上为测试项目设置目标成员资格。一旦完成,我们就可以通过静态结构调用来调用这些方法。

需要注意的一点是,Bundle init 可能会根据您的调用方式提供一些意想不到的功能。如果您计划在测试用例之外测试其他包,则可能需要对其进行更改。

还有一点值得注意的是,其中两个方法接受字符串输入,因此可以将它们重构为字符串扩展。

extension String 
    func csv() -> [[String]] 
        var result: [[String]] = []
        let rows = self.components(separatedBy: "\n")
        for row in rows 
            let columns = row.components(separatedBy: ",")
            result.append(columns)
        
        return result
    

    func cleanRows()->String
        var cleanFile = self
        cleanFile = cleanFile.replacingOccurrences(of: "\r", with: "\n")
        cleanFile = cleanFile.replacingOccurrences(of: "\n\n", with: "\n")
        return cleanFile
    

因此,如果您将上述扩展名放入新的 CSVTestUtility 文件中,您将能够直接从您正在使用的字符串中访问方法,例如:

var csvData = "somedata"
var csvConvertedData = csvData.csv()
for row in csvConvertedData 
    row.cleanRows()

如您所见,帮助程序和实用程序是帮助单元测试共享通用功能的宝贵工具,但与往常一样,请确保您的工作易于识别,这样您就可以了解未来的意图是什么对项目新鲜。

【讨论】:

let bundle = Bundle(for: type(of: self)) 是我在这里找到的问题。它显示错误“无法将'CSVTestUtility.Type.Type'类型的值转换为预期的参数类型'AnyClass'(又名'AnyObject.Type')” 解决了 Bundle 的问题。它还致力于将 CSVTestUtility 从 Struct 更改为 Class。 您可以这样做,也可以使用type(of: self) as! AnyClass 将调用投射到 AnyClass。两者都可以。

以上是关于Xcode 单元测试 - 添加一个用于所有测试类的通用函数的主要内容,如果未能解决你的问题,请参考以下文章

将单元测试移动到 xcode 中的不同文件夹

从 Xcode 项目中删除单元测试?

XCode 5.1 单元测试覆盖分析在使用块的文件上失败

测试类的包返回 Xcode 10 中的主包,而不是单元测试包

单元测试很棒,但是

删除 XCode 8 中的单元测试