簡體   English   中英

目標C - 具有多個測試輸入的單元測試的最佳實踐

[英]Objective C - Best practice for Unit Testing with multiple test inputs

我正在為現有項目編寫單元測試代碼。 該項目是在Objective-C中,我必須測試幾個函數,其中包含對測試用例的大量輸入。 例如,我有一個測試用例來測試函數計算器,其中輸入了兩個參數。 目前我創建數組來存儲輸入值集以運行測試。 使用的代碼如下:

- (void)setUp {
    [super setUp];
    self.vcToTest = [[BodyMassIndexVC alloc] init];
    input1 = [[NSMutableArray alloc] initWithObjects:@"193", @"192", @"192", @"165", @"155", @"154", nil];
    input2 = [[NSMutableArray alloc] initWithObjects:@"37", @"37", @"36", @"80",@"120", @"120", nil];
}



- (void)testCalculatorSuccess {
    for (int i=0; i<input1.count; i++) {
        NSArray *expectedResult = [[NSArray alloc] initWithObjects: @"9.93", @"10.04", @"9.77", @"29.38", @"49.95", @"50.60", nil];
        NSString *actualResult = [self.vcToTest calculateResult:input1[i] andInput2:input2[i]];
        XCTAssertEqualObjects(actualResult, expectedResult[i]);
    }

}

我在網上搜索了最佳實踐,但未能找到任何。 有人可以幫我弄這個嗎? 我是否以正確的方式進行測試? 在這種情況下,最佳做法是什么? 我應該為每組輸入創建一個測試用例嗎?

您的測試類應該針對一個特定的東西來測試哪個是sut(被測系統)。 在你的情況下,sut變量應該是你的vcToTest。 我將進行測試的方式是通過依賴注入,而不是將您正在測試的所有數組存儲為實例變量。 因此,您將創建一個測試方法,該方法接收您要測試的參數。 這樣您就不需要繼續創建實例變量,只需創建與測試方法相關的局部變量。

- (void)setUp {
    [super setUp];
    // Put setup code here. This method is called before the invocation of each test method in the class.
    self.sut = [[BodyMassIndexVC alloc] init];
}

- (void)tearDown {
    // Put teardown code here. This method is called after the invocation of each test method in the class.
    self.sut = nil;
    [super tearDown];
}

- (void)testBMIFormulaInCmAndKgSuccess {
    // local variables that are only seen in this method 
    NSArray *heightsInMetres = [[NSMutableArray alloc] initWithObjects:@"193", @"192", @"192", @"165", @"155", @"154", nil];
    NSArray *weightsInKg = [[NSMutableArray alloc] initWithObjects:@"37", @"37", @"36", @"80",@"120", @"120", nil];
    NSArray *expectedResults = [[NSArray alloc] initWithObjects: @"9.93", @"10.04", @"9.77", @"29.38", @"49.95", @"50.60", nil];
    for (int i=0; i<heightsInMetres.count; i++) {
        [self xTestHeightInMeters:heightsInMetres[i] weightInKg:weightsInKg[i] expecting:expectedResults[i]];
    }
}

// the variables that are used to test are injected into this method
- (void)xTestHeightInMeters:(NSString *)height weightInKg:(NSString *)weight expecting:(NSString *)expectedResult {
    NSString *result = [self.sut calculateBMIforHeight:height andWeight:weight];
    XCTAssertEqual(result, expectedResult);
}

如果我是你,我不會創建數組來運行測試。 數組很亂,很難理解發生了什么,容易犯錯誤。 我會創建特定的測試方法,測試一件事,以確保sut正常工作。 例如,在TDD中,您創建了一個失敗的測試方法,然后修改您的sut以最簡單的方式修復此故障。 通常這意味着您的修復將完全返回您期望的內容。 然后你做另一個用不同的值測試完全相同的東西的測試,它現在應該失敗,因為你的sut只是返回他們之前的測試所尋找的東西。 現在你再次修改你的sut以使兩個測試都通過。 在大多數情況下,您不需要任何額外測試,因為它已被證明可以兩種獨特的方式工作。

我知道你說你正在測試已經編寫的軟件,但我強烈建議你查看測試驅動開發。 即使您實際上沒有應用TDD,您也將學習如何創建有意義的測試。 這有助於我學習tdd

根據我的經驗,關鍵考慮因素應該是隨着時間的推移維護測試套件是多么容易。 您當前的方法將以兩種方式引發問題:

  1. 如果要為BMI計算使用不同的數字,則需要使用不同的測試類(因​​為您將鎖定設置方法中的值)。

  2. 如果您決定使用不同的數學或多個BMI方程,則必須在檢查這些值的任何位置更新數組。

我建議改為創建一個CSV或純文本文件,其中包含高度,重量和預期的BMI值。 這使測試數據保持在一起。 然后在您的測試方法中,加載文件並檢查您的實際BMI與預期的BMI。

您可以靈活地混合和匹配測試數據,或者為不同的BMI方程使用不同的測試文件。 就個人而言,我也喜歡這樣一個事實,即如果您想要回滾或添加遺留算法支持,您可以在更改內容時保留舊數據文件。

一個快速和臟的版本看起來像這樣:

- (NSArray *)dataFromFileNamed:(NSString *)filename {
    NSString *path = [[NSBundle bundleForClass:[self class]] pathForResource:filename ofType:nil];
    // load the data however its formatted
    // return the data as an array
    return loadedData;
}

- (void)testBMIFormulaInCmAndKgSuccess {
    NSArray *testData = [self dataFromFileNamed:@"BMI_data_01.txt"];
    for (int i=0; i < testData.count; i++) {
        NSArray *dataSet = testData[i];
        CGFloat height = dataSet[0];
        CGFloat weight = dataSet[1];
        CGFloat expectedBMI = dataSet[2];
        NSString *actualResult = [self.vcToTest calculateBMIforHeight:height andWeight:weight];
        XCTAssertEqual(actualResult, expectedBMI);
    }
}

通常最好避免單元測試代碼中的for循環。 此規則通常會導致單獨的斷言。

但在您的情況下,您希望使用各種輸入來執行功能。 你的方法一點也不差。 我們可以使用文字來簡化數組:

NSArray<NSString *> *heightsInMetres = @[ @"193",   @"192",  @"192",   @"165",   @"155",   @"154"];
NSArray<NSString *> *weightsInKg =     @[  @"37",    @"37",   @"36",    @"80",   @"120",   @"120"];
NSArray<NSString *> *expectedResults = @[@"9.93", @"10.04", @"9.77", @"29.38", @"49.95", @"50.60"];

我通常也會避免有趣的格式化。 但是對齊列有助於我們以類似表格的格式查看值。

最后,我不會將這些值放在setUp除非它們用於多個測試。

如果您需要這樣的許多測試,可能值得探索使用實際表格的測試格式,例如Fitnesse 表數據可以是電子表格或wiki格式,也可以用於測試。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM