单元测试 UITextField 上的操作

Posted

技术标签:

【中文标题】单元测试 UITextField 上的操作【英文标题】:Unit test an action on UITextField 【发布时间】:2012-08-20 01:47:34 【问题描述】:

我有一个简单的 if 条件,当满足时,添加一个目标以在点击“完成”时放下键盘

- (void)addDoneWhenTrue:(UITextField *)input

    if (YES)
    
        [input addTarget:self action:@selector(textFieldFinished:) forControlEvents:UIControlEventEditingDidEndOnExit];
    


- (IBAction)textFieldFinished:(id)sender

    [sender resignFirstResponder];

我在 ios5 上使用 OCMock 和 OCUnit。如何创建一个单元测试,允许我传入一个简单的UITextField 输入并模拟点击其上的完成按钮以验证resignFirstResponder 是否发生(或不发生)?

【问题讨论】:

我想我可以帮助您进行测试,但首先,您为什么要添加此目标/操作?为什么不直接用if (theCondition) [self.textField resignFirstResponder]; 实现textFieldShouldReturn: 有趣 - 不确定我是否有真正的理由使用上面的实现(只是希望基本键盘上的 DONE 按钮在点击时将其放下......你拥有的任何东西都是可测试的并且这样做为我工作) 【参考方案1】:

您不需要模拟它,这种目标/行动方法感觉就像是一种真正迂回的方式来获得您想要的东西。只要您的控制器是UITextField 的代表,textFieldShouldReturn: 就会在点击 Return(或本例中的 Done)键时被触发。

#pragma mark - UITextFieldDelegate

-(void)textFieldShouldReturn:(UITextField *)textField 
    if (someConditionThatDeterminesWhetherKeyboardShouldCollapse) 
        [textField resignFirstResponder];
    

然后,当您的条件满足和不满足时,您可以在控制器上测试调用textFieldShouldReturn:。如果需要,您还可以通过调用 loadView 确保您的视图已加载到测试用例中,然后断言文本字段的委托是您的控制器,这将确保视图正确连接。

-(void)testDoneShouldCollapseKeyboard 
    [controller loadView];
    expect(controller.textField.delegate).to.beIdenticalTo(controller);

    id mockTextField = [OCMockObject partialMockForObject:controller.textField];
    [[mockTextField expect] resignFirstResponder];
    controller.someConditionThatDeterminesWhetherKeyboardShouldCollapse = YES;

    [controller textFieldShouldReturn:controller.textField];

    [mockTextField verify];

    [[mockTextField reject] resignFirstResponder];
    controller.someConditionThatDeterminesWhetherKeyboardShouldCollapse = NO;

    [controller textFieldShouldReturn:controller.textField];

    [mockTextField verify];

【讨论】:

您有机会再澄清一下吗?我没有直接在这个控制器上直接设置委托(只有输入的目标,但我不确定如何测试它)。另外,如果我调用 textFieldShouldReturn (但不实现这个......)我错过了什么吗?我目前只有上面显示的 textFieldFinished 更新了示例代码。如果要处理 Done 键,则需要在文本字段上设置委托。委托通常是您的控制器。 当你说“点击完成时”,你的意思是键盘右下角的键,对吧? 是的 - 完全正确(我仍然想了解您上面的精彩帖子) 看看developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/…【参考方案2】:

当然,您不需要模拟单击按钮,因为这是 UIKit 正在处理的事情。您担心当调用 textFieldFinished: 方法时会发生正确的事情

免责声明

我很长时间没有使用OCMock,所以这是一个仅使用文档的示例,因此很容易出现轻微错误 - 希望有人可以纠正拥有OCMock 的所有设置。

id mock = [OCMockObject mockForClass:[UITextField class]];

[[mock expect] resignFirstResponder];

[sut textFieldFinished:mock]; // sut = system under test - taken from your screen cast ;)

[mock verify];

【讨论】:

我实际上是在寻找一种方法来执行 input.click,然后使用 ocmock 断言 resignFirstResponder 被调用(使用部分模拟)。很好奇是否有人能够做到这一点,因为它会产生更高级别/更不易碎的单元测试恕我直言 那将是一个集成测试——通常比单元测试更脆弱?我不确定我在单元测试UIKit 组件中看到的价值。仔细看看你的代码,我想知道你为什么不使用UITextFieldDelegate 方法- (void)textFieldDidEndEditing:(UITextField *)textField?然后,如果您必须进行单元测试,您可以确保在某些时候您正在使用正确的委托对象设置 textField 我们当然可以争论在这种情况下单位/积分是否正确。我可以说的是,我正在寻找另一种方式来断言这一点,这种方式不那么特定于实现,而是特定于行为。我写了像你一遍又一遍提到的断言,同样的事情打动了我——如果我在写这个测试时首先考虑到行为,为什么我不断言它会掉键盘?只是问,因为我总是希望改进,而这个测试(我一遍又一遍地写)让我觉得我可以做得更好 我不确定是否有更好的方法 - 您正在测试您的代码单元并希望 UITextField 的黑匣子确实将其称为委托,然后您也希望 @ 987654330@ 实际上会移除键盘。因此,如果一切都正确连接(您可以测试),那么委托方法 textFieldDidEndEditing: 将被调用,然后您可以测试它。

以上是关于单元测试 UITextField 上的操作的主要内容,如果未能解决你的问题,请参考以下文章

在 git push 操作后触发 Bamboo 单元测试

通过单击不同的单元格来更改详细视图上的 UITextfield

自动化单元测试工具目前常用的都有哪些?

UITableViewCell 中的 UITextField 使用自动布局

开关盒上的 iOS 单元测试

在 ViewController 中可观察到的单元测试 RxSwift