Naveen George Thoppan
Naveen George Thoppan

Reputation: 571

Xcode Unit Testing - Add a common function to be used across all test classes

I've implemented unit testing for my project using Swift. In the test cases, I'm reading input values are results from a CSV file and validates them. Currently all the functions to read the CSV file and parse it needs to be copied and pasted to the new test class whenever I create a new test case class. Is there some way to use the functions to read the CSV file at one place so that all test classes can use them? The code I would like to reuse is :

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
    }
}

Upvotes: 1

Views: 1803

Answers (1)

jlowe
jlowe

Reputation: 318

You would be able to handle this with a Helper file. You can use a static function and extensions to accomplish this.

To begin, add a new swift file to your test project, preferably named something descriptive, in this case CSVTestUtility or CSVTestHelper are reasonable.

Next we would want to create a struct that would contain these methods.

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
        }
    }

At this point we want to make sure that the file is added to the Unit Test project, so make sure the target membership is set on the file for the Test project. Once it is, we would be able to call these methods through static struct calls.

One thing to note that the Bundle init might provide a little bit of unintended functionality based on how you are looking to call it. If you are planning on testing other bundles outside of the test case, it may have to be altered.

One thing that is also noticeable is that two of these methods take string inputs, so these could be refactored into a String extension.

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
    }
}

So if you were to put the above mentioned extension in your new CSVTestUtility file, you would be able to access the methods directly off of the strings that you were working with, for example:

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

As you can see, helpers and utilities are valuable tools for helping unit tests share common functionality, but as always, make sure your work is easily identifiable so you can understand what the intent is in the future when you might not be so fresh on the project.

Upvotes: 1

Related Questions