我似乎无法模拟NSUserDefaults。我希望它能够发回我告诉它的数据,但它会在运行应用程序时发回存储在其中的数据。
我正在使用:
Specta
Expecta
OCMockito
我有以下测试:
describe(@"AppDelegate", ^{
__block AppDelegate *appDelegate;
beforeEach(^{
appDelegate = [AppDelegate new];
});
afterEach(^{
appDelegate = nil;
});
describe(@"application did finish launching with options", ^{
beforeEach(^{
[appDelegate application:nil didFinishLaunchingWithOptions:nil];
NSUserDefaults *mockUserDefaults = mock([NSUserDefaults class]);
[given([mockUserDefaults objectForKey:@"currentUser"]) willReturn:nil];
});
it(@"should have a login view controller as root view controller", ^{
expect(appDelegate.window.rootViewController).to.beKindOf([ToALoginViewController class]);
});
});
});
所以上面的测试失败了,因为它实际上返回了currentUser
的一些数据。我做错了什么?
继Ken Kuan所说的之后,我做了以下修改:
AppDelegate.h
@property (strong, nonatomic) NSUserDefaults *userDefaults;
- (void)setUserDefaults:(NSUserDefaults *)userDefaults;
AppDelegate.m
- (void)setUserDefaults:(NSUserDefaults *)userDefaults {
_userDefaults = userDefaults;
}
AppDelegateSpec.m
beforeEach(^{
[appDelegate application:nil didFinishLaunchingWithOptions:nil];
NSUserDefaults *mockUserDefaults = mock([NSUserDefaults class]);
[appDelegate setUserDefaults:mockUserDefaults];
[given([mockUserDefaults objectForKey:@"currentUser"]) willReturn:nil];
});
但是,我仍然遇到同样的问题。
答案 0 :(得分:3)
你可以模仿NSUserDefaults
。我有这个代码,工作正常。
当你嘲笑NSUserdefaults
时,请确保在测试用例结束时停止模拟,否则会导致您使用NSUserDefaults
的其他地方出错。
id userDefaultsMock = OCMClassMock([NSUserDefaults class]);
OCMStub([userDefaultsMock standardUserDefaults]).andReturn(userDefaultsMock);
OCMStub([[userDefaultsMock standardUserDefaults] boolForKey:SHOWMYNAME]).andReturn(@"N");
[self.myObject codewithuserdefaults];
OCMVerify( [[NSUserDefaults standardUserDefaults] setValue:[OCMArg any] forKey:FIRSTNAME]);
[userDefaultsMock stopMocking];
答案 1 :(得分:1)
您必须在appDelegate中使用[NSUserDefaults standardUserDefaults]
,这是实际的用户默认值,而不是您的模拟。
解决方案是将用户默认设置为app delegate的属性,并在测试中使用mockUserDefaults
进行设置。
另一个是调动[NSUserDefaults standardUserDefaults]
以在测试中返回mockUserDefaults
。
答案 2 :(得分:1)
非常感谢Ken Kuan,我设法解决了我遇到的问题。以下是我如何实现它。
我在NSUserDefaults
和setter函数中添加了AppDelegate
属性。
我在self.userDefaults
中将[NSUserDefaults standardUserDefaults]
设置为application:willFinishLaunchingWithOptions:
。
然后我在rootViewController
application:didFinishLaunchingWithOptions:
<强> AppDelegate.h 强>
@property (strong, nonatomic) NSUserDefaults *userDefaults;
- (void)setUserDefaults:(NSUserDefaults *)userDefaults;
<强> AppDelegate.m 强>
- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.userDefaults = [NSUserDefaults standardUserDefaults];
return YES;
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
NSData *encodedUserData = [self.userDefaults objectForKey:@"currentUser"];
if (encodedUserData) {
NSLog(@"Have current user");
self.window.rootViewController = [ThermostatViewController new];
} else {
NSLog(@"No current user");
self.window.rootViewController = [ToALoginViewController new];
}
[self.window makeKeyAndVisible];
return YES;
}
- (void)setUserDefaults:(NSUserDefaults *)userDefaults {
_userDefaults = userDefaults;
}
<强> AppDelegateSpec.m 强>
describe(@"application will finish launching with options", ^{
beforeEach(^{
[appDelegate application:nil willFinishLaunchingWithOptions:nil];
});
context(@"application did finish launching with options and with no current user", ^{
beforeEach(^{
NSUserDefaults *mockUserDefaults = mock([NSUserDefaults class]);
[appDelegate setUserDefaults:mockUserDefaults];
[given([mockUserDefaults objectForKey:@"currentUser"]) willReturn:nil];
[appDelegate application:nil didFinishLaunchingWithOptions:nil];
});
it(@"should have a login view controller as root view controller", ^{
expect(appDelegate.window.rootViewController).to.beKindOf([ToALoginViewController class]);
});
});
});