使用设置在单元测试中重置类值的正确方法

时间:2016-03-11 01:13:58

标签: objective-c unit-testing

我是Objective-C的新手,所以请耐心等待。

我有一个单元测试类,看起来像这样:

static NSString * const kTestingUserID = @"userID";    

@interface UserPreferencesTest

@property(nonatomic) UserPreferences *userPreferences;

@end

@implementation UserPreferencesTest

- (void)setUp {
  [super setUp];
  self.userPreferences = [[UserPreferences alloc] init];
}

- (void)testEmptyDictionary {
  STAssertFalse([self.userPreferences getLockoutStatus:kTestingUserID],
               @"An unset username should always return false");
}

- (void)testBlockManualEntry {
  //lock the username
  [self.userPreferences lockout:kTestingUserID];

  STAssertTrue([self.userPreferences getLockoutStatus:kTestingUserID],
                @"The account has been locked out");
}

@end

他们在userPreferences类中调用以下方法:

- (void)lockout:(NSString *) userID {
  NSMutableDictionary *dictionary =
      [[self.defaults objectForKey:dict] mutableCopy];
  dictionary[userID] = [NSNumber numberWithBool:YES];
  [self.defaults setObject:[NSDictionary dictionaryWithDictionary:dictionary]
                    forKey:dict];
  [self synchronize];
}

- (BOOL) getLockoutStatus:(NSString *) userID {
  NSDictionary *dictionary = [self.defaults objectForKey:dict];
  if ([dictionary objectForKey:userID])
    return true;
  return false;
}

如果我注释掉testBlockManualEntry,测试就会通过。如果我在第一个测试中同时运行两个测试,则testEmptyDictionary会失败。我理解的问题是用户名是在第二次测试中设置的,然后在第一次测试中找到。

如果我在java中编写类似的单元测试,我会在我的设置中使用@Before,因此在调用每个测试方法之前就会运行设置。这将确保每次都创建userPreferences,从而重置该对象中的值。

我在这里缺少什么?我对Objective-C中的设置的理解是它应该表现得相似(显然它除非是我没见过的另一个bug)。

另外请忽略这样一个事实:在这种情况下,一个集合比dict更好用,我只是在寻找(以及如何解决问题)为什么测试在一起运行时失败。

1 个答案:

答案 0 :(得分:2)

我建议改用Xcode的XCT测试框架。 SN *是一个旧框架。

您的问题可能来自

@interface UserPreferencesTest

应该是

@interface UserPreferencesTest: XCTestCase

这样它就可以继承测试框架的所有功能。然后它应该工作。

我也注意到了这段代码:

if ([dictionary objectForKey:userID])
    return true;
return false;

此代码没有任何问题,它可以正常工作。但从风格的角度来看,我会改变它。首先,我始终建议确保if ...语句始终具有{...}括号。原因是很容易错过读取单行if并且会出现细微的错误,特别是如果其他开发人员正在更新您的代码。

第二件事是每当我看到return YESreturn NO时,我倾向于查看它们是否是代码试图实现的详细版本。 有鉴于此,我可能会编写类似这样的代码:

return [dictionary objectForKey:userID] != nil;

话虽如此,当您return YESreturn NO时,有时代码会更清晰。所以你对此感觉如何。