iOS单元测试按钮已分配操作

时间:2015-12-11 10:47:34

标签: ios unit-testing

我已经以编程方式编写了以下按钮:

self.button = [[UIButton alloc] init];
[self.button setTitle:@"Reverse String!" forState:UIControlStateNormal];
self.button.backgroundColor = [UIColor colorWithRed:0.2 green:0.2 blue:0.2 alpha:1.0];
self.button.layer.cornerRadius = 5.0;
[self.button addTarget:self action:@selector(reverseString:) forControlEvents:UIControlEventTouchUpInside];

但是,当我尝试测试时,我的单元测试失败了:

-(void)testButtonActionAssigned
{
    XCTAssert([self.vc.button respondsToSelector:@selector(reverseString:)]);
}

我收到一条失败的消息说:

  

测试失败: - [ViewControllerTests testButtonActionAssigned]失败:   (([self.vc.button respondsToSelector:@selector(reverseString :)])是   真的)失败

我的设置方法叫做:

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

    NSLog(@"THIS METHOD IS CALLED");
}

是否与模拟器定时和启动有关?

2 个答案:

答案 0 :(得分:1)

[self.button addTarget:self action:@selector(reverseString:) forControlEvents:UIControlEventTouchUpInside];   

第一行表示reverseString:方法应该在ViewController中(由target:参数指定,并在那里传递self)。因此,只需删除.button

即可更改测试
 -(void)testButtonActionAssigned
    {
        XCTAssert([self.vc respondsToSelector:@selector(reverseString:)]);
    }

以下是可以更改的小例子:

UIButton *button = [UIButton new];
[button addTarget:self action:@selector(doThat:) forControlEvents:UIControlEventTouchUpInside];

NSString *selectorString = [[button actionsForTarget:self forControlEvent:UIControlEventTouchUpInside] firstObject];

SEL sel = NSSelectorFromString(selectorString);

// so now you can check if target responds to selector
// BOOL responds = [self respondsToSelector:sel];

NSLog(@"%@", selectorString);

答案 1 :(得分:0)

我明白了。我正在测试错误的东西。

问题中的代码并未真正测试按钮是否已分配操作。它基本上是说“视图控制器是否响应此方法”或“视图控制器是否具有此方法”。

po UIApplication.sharedApplication().keyWindow!._firstResponder()

这意味着无论按钮是否指定了选择器,只要定义了该方法,该断言始终为真。

我通过评论代码行验证了它:

// this is saying "does the ViewController know about this method"
// rather than "is ViewController's button assigned method reverseString:"
XCTAssert([self.vc respondsToSelector:...]);

并且测试仍然通过,这不是我想要实现的目标。

正确的测试应为:

[self.button addTarget:self action:@selector(reverseString:) forControlEvents:UIControlEventTouchUpInside];

现在评论出来之后:

-(void)testButtonActionAssigned
{
    [self.vc viewDidLoad];

    NSArray *arrSelectors = [self.vc.button actionsForTarget:self.vc forControlEvent:UIControlEventTouchUpInside];

    NSString *selector = nil;

    if(arrSelectors.count > 0)
    {
        selector = arrSelectors[0];
    }

    XCTAssert([selector isEqualToString:@"reverseString:"]);
}

测试按预期失败:D

这个正确的测试代码从按钮中取出选择器并检查它是否确实是名为[self.button addTarget:self action:@selector(reverseString:) forControlEvents:UIControlEventTouchUpInside]; 的方法

修改

B.S.回答,并通过Apple的文档确认,更短的版本可以写成:

reverseString:

我原本担心在空数组上调用firstObject会导致应用程序崩溃,但Apple的文档向我确认firstObject是一个属性,如果数组为空则返回nil。

  

数组中的第一个对象。 (只读)

     

声明@property(非原子,只读)ObjectType firstObject

     

讨论如果数组为空,则返回nil。

https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSArray_Class/#//apple_ref/occ/instp/NSArray/firstObject