测试/模拟UIAlertView,从视图控制器

时间:2015-08-15 18:01:34

标签: ios objective-c uialertview ocmock

我在视图控制器中为performLogin方法编写测试,我不能重构原始方法,也不能重构项目中的任何其他文件。我只能修改我的LoginTest.m文件。我正在尝试使用OCMock来完成此测试,而无需更改原始程序文件。

我正在尝试验证如果performLogin方法收到异常,则会显示UIAlertView。 ViewHelper类有一个返回void的类方法,并创建并显示UIAlertView。

我已经模拟了调用ViewHelper的视图控制器,我尝试使用OCMock使用各种搜索中的示例来测试UIAlertView类,但是这些测试失败了,因为它没有捕获AlertView的创建。

我是使用OCMock的新手,我不知道如何为这种类型的测试模拟ViewHelper文件,特别是因为它是从方法中调用而不是锚定到属性。

可能有一种简单的方法可以做到这一点,但我还没弄清楚,任何帮助都会受到赞赏。

提前感谢。

在调用doLogin时,方法内部返回TRUE或抛出异常。当抛出异常时,它应该弹出带有消息的UIAlertView。我想测试代码的这一部分并验证实际显示的是UIAlertView。

请注意,ViewHelper直接从catch块中调用。

方法如下:

-(IBAction)performLogin:(id)sender {
  if(valid) 
  {
    @try
    {
      //loginModel is a private instance variable
      loginModel = [[Services sharedInstance] getLoginModel];
      [loginModel doLoginWithUsername:username andPassword:password];
      [self performSegueWithIdentifier:@"showWelcomeScreen" sender:self];
    }
    @catch(NSException *e)
    {

      //I NEED TO TEST THAT THIS CALL OCCURS AND THE UIAlertView is shown
      //Not sure how to do this as it's not anchored to a property or method
      //and is called as a class method

      [ViewHelper showAlertForTitle:"Error" andTheMessage:@"network error"
        andAccessibilityLabel:@"Network Error"];
    }
   }
}

ViewHelpder.m看起来像这样 - 注意,它是一个类方法:

+(void) showAlertForTitle:(NSString *)title andTheMessage:(NSString *)message      andAccessibilityLabel:(NSString *)label
{
    NSLog(@"reached alert notification class");
    UIAlertView *successAlert = [[UIAlertView alloc] initWithTitle:title  message:message delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
    [successAlert setAccessibilityLabel:label];
    [successAlert show];
}

除此之外,我到目前为止已尝试过:

- (void)testForfailedLogin {

    //call singleton first to initialize mocked login model
    [[Services sharedInstance] getLoginModel];

    id mockAlertView = [OCMockObject mockForClass:[UIAlertView class]];
    [[[mockAlertView stub] andReturn:mockAlertView] alloc];
    (void)[[[mockAlertView expect] andReturn:mockAlertView]
       initWithTitle:OCMOCK_ANY
       message:OCMOCK_ANY
       delegate:OCMOCK_ANY
       cancelButtonTitle:OCMOCK_ANY
       otherButtonTitles:OCMOCK_ANY, nil];
    [[mockAlertView expect] show];


    //set the actual IBOutlets with login values designed to sucessfully login
    self.controller.usernameTextField.text = @"error";
    self.controller.passwordTextField.text = @"error";

    //call the login process to verify the login method
    [self.controller performLogin:nil];

    [mockAlertView verify];
    [mockAlertView stopMocking];

}

1 个答案:

答案 0 :(得分:1)

我不记得OCMock apis已经确定无法编译,但我相信这个想法是正确的。 (我基本上跟随this guide

首先,最好通过两次测试来测试它。 第一个测试将仅检查在异常时调用[ViewHelper showAlertForTitle:"Error" andTheMessage:@"network error" andAccessibilityLabel:@"Network Error"]。第二个测试将在调用+[ViewHelper showAlertForTitle:andTheMessage:andAccessibilityLabel:]时检查是否出现警报视图(或者您希望发生的任何其他事情)。

第一次测试的(重要部分):

// ① You need to setup something to raise an exception
// so the catch block will be called
// Probably you want to use [OCMArg any] or [OCMArg anyPointer]
OCMStub([mockServices loginWithUsername:[OCMArg isNotNil]
                            andPassword:[OCMArg isNotNil]])
  .andThrow(anException);

// ② Call your method
// sender can be nil in your code.
[controller performLogin:sender]; 

// ③ Expect your method to be called
OCMExpect([mockViewHelper showAlertForTitle:"Error" 
                              andTheMessage:@"network error"
                      andAccessibilityLabel:@"Network Error"]);

// ④ Verify
OCMVerifyAll(mockViewHelper)

第二次测试的要点:

// ① Stub everything you want to check to be called inside 
// `+[ViewHelper showAlertForTitle:andTheMessage:andAccessibilityLabel:]`
// probably your UIAlertView, etc
id mockAlertView = ...

// ② Call your method
[ViewHelper showAlertForTitle:@"something" 
                andTheMessage:@"something" 
        andAccessibilityLabel:@"something"]; 

// ③ Expect your stuff to be called
OCMExpect([mockAlertView someMethod]);

// ④ Verify
OCMVerifyAll(mockAlertView)

最后一点,在objc世界中,Exceptions用于程序员错误,如果你设计这些类,则考虑像许多其他Cocoa API一样返回NSError。