单元测试 - 要测试什么?

时间:2013-11-18 12:50:55

标签: iphone objective-c unit-testing

所以,我已经对Xcode中单元测试和创建测试用例/套装的优点做了一些阅读。我可以看到这样做的好处,可以避免像回归这样的事情,并确保新的提交/构建不会破坏现有的代码。

我想弄清楚的是 - 我该测试什么?

我是否为我创建的每个类创建测试?

目前,我正处于项目的开始阶段,我正在忙于创建大量的模型对象 - 这些类没有那么多 - 主要是为了保存我解析的数据(来自XML)。我应该创建测试用例以确保满足每个对象的每个要求吗?

以上面的例子为例 - 如果我为我的一个模型对象写了一个这样的测试套装:

import <XCTest/XCTest.h>
#import "BBError.h"

@interface ErrorObjectTests : XCTestCase

@end

@implementation ErrorObjectTests
{
    BBError *error;
}
- (void)setUp
{
    [super setUp];
    // Put setup code here; it will be run once, before the first test case.
    error = [[BBError alloc]init];
}

- (void)tearDown
{
    // Put teardown code here; it will be run once, after the last test case.
    [super tearDown];

   error = nil; 
}


-(void)test_HasValidErrorCodeMessage
{
    error.code = @"Error Code";

    XCTAssertEqual(error.code, @"Code error",
                   @"BBError should have valid error code message");

}

现在,如果由于某种原因在我的应用程序中 - 我将error.code设置为nil或者没有为其分配错误代码 - 那么此测试会失败吗?

我无法理解为什么它会失败 - 因为在实际的测试方法中 - 我将error.code分配给字符串值。我应该保留这个值,然后我使用这个对象,确保error.code有一个值,以便测试通过?

P.S:是的,我知道这个特定的测试可能不是最准确的,因为我可能并不总是首先得到错误 - 但这只是一个例子

欣赏任何输入人物。

2 个答案:

答案 0 :(得分:2)

当您开始进行单元测试时,最重要的是编写它们。由于截止日期不可测试的代码缺乏同事支持,因此很容易在开始时大肆宣传然后逐渐放弃这个想法什么不是,特别是如果你被测试一切获得99%的覆盖建议所震惊。最好保持务实,专注于最有可能受益的领域,比如说:

  • 测试关键应用程序功能(大多数业务逻辑)
  • 测试你期望的东西可能会有问题/在过去被证明是有问题的
  • 通过其他方式测试难以/耗时测试的东西
  • 不测试数据持有者对象(如POCO);他们很少带有任何逻辑,测试它们几乎没有增加价值

error.code测试示例带到这些点,然后尝试自己决定。

实施例

  

测试关键应用程序功能(大多数业务逻辑)

有人可能会争辩说,任何对应用程序工作/功能都不重要的代码都不应该存在。这可能听起来很吸引人,但事实上有很多代码可以帮助开发人员减少生活或帮助解决不一定有助于功能开发的常见问题。你测试这样的代码吗?并不总是 - 如果我重构了一个将3个语句合并为一个的方法,因为它们通常一起被发现,我可能想跳过测试。

  

测试你认为有问题的东西/在过去被证明是有问题的

这很简单。我们致力于有限的资源(即时间);在现实世界的情景中,测试一切往往是太田园诗般的想法。很多时候,你会发现自己必须做出决定,无论一段代码是否会编写测试。当这样的时候到来时,喜欢复杂的代码比简单的代码。确定某些事情是否复杂当然是判断力,在很大程度上取决于你的经验。但我想大多数人都可以对以下哪种方法处理问题做出正确的猜测:

PrintLineToFile(string filePath, string line)
ComputeUserRisk(User user, RiskAssessment previousResult)

另外,如果我可以快速浏览一下简单的代码,并且确信它能够像我期望的那样工作,那么我可能会跳过单元测试(但同样,这是紧急期限/稀疏资源次。)

  

通过其他方式测试难以/耗时的测试

事实上,只需运行应用程序并单击按钮/执行命令,人工测试人员就可以对所有内容进行半自动测试。但请注意,某些代码很难到达。如果为了测试NumbersConverter你需要将文件上传到服务器,加载任务创建者,构建新任务并安排它从现在开始运行30秒,因为这是你需要连接调试器的最短时间......然后你应该考虑对此类NumbersConverter进行单元测试,并且每次返回3.15而不是3.16时都不要手动运行完整的方案。

结论

不幸的是,没有“这样做而且不这样做”-rule - 你必须根据项目类型,领域,团队,工具以及可能的许多方法来发展自己的方法其他因素。一些项目/领域需要更严格的测试,其他项目/领域允许更多的松弛与所有事情一样,总是尝试查看您正在做的事情(单元测试)的上下文,并尝试预测哪些操作(测试)将在给定时间内最大程度地受益(aka adapt )。

答案 1 :(得分:0)

单元测试的目的是断言你的班级在某些事情发生时会按照你的期望行事。您正在测试您的逻辑是否正确。您没有对整个应用进行测试。

示例代码测试的更好名称可能是

-(void)testErrorObjectHasValidCodeAtInitialisation

因为您的测试实例化BBError,然后针对其代码属性运行测试。

如果在将来的某个时候您将默认的BBError代码更改为“冒险时间”,那么测试将告诉您更改已经过,如果您不打算这样做,那么您可以修复错误。

简而言之,您可以独立于应用程序测试逻辑。

测试什么。测试逻辑。

一个简单的例子。

@implementation Foo

-(NSInteger)gimmeASeven
{
    return 7;
}

@end

测试可能是。

-(void)testThatGimmeASevenReturnsSeven {

    Foo *testFoo = [[Foo alloc] init];

    NSInteger actualReturn = [testFoo gimmeASeven];

    NSInteger expectedReturn = 7;

    XCTAssertEqual(actualReturn, expectedReturn, @"method did not return 7 - why not?");


}

它与App无关。该测试确保给定的类/方法始终执行您期望的操作。

你应该创建测试。这取决于您以及您希望您的产品如何发展和可维护。我无法回答这个问题。

相关问题