我在视图控制器中为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];
}
答案 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。