我的一个单元测试失败了,原因是我没有预料到。似乎对isKindOfClass
的调用返回NO,但是当我调试并逐步执行时,似乎没有理由这样做。
代码是:
if ([self.detailItem isKindOfClass:[MovieInfo class]]) {
[self configureViewForMovie];
}
我完成了代码并做了:
po self.detailItem
显示:
(id) $1 = 0x0ea8f390 <MovieInfo: 0xea8f390>
那么,我错过了什么,为什么在这种情况下if语句会返回false?
编辑:
这是DetailItem的setter:
- (void)setDetailItem:(id)newDetailItem
{
if (_detailItem != newDetailItem) {
NSLog(@"%@", [newDetailItem class]);
_detailItem = newDetailItem;
// Update the view.
[self configureView];
}
if (self.masterPopoverController != nil) {
[self.masterPopoverController dismissPopoverAnimated:YES];
}
}
它是Master Detail模板中的模板代码。
单元测试在setUp:
中创建一个MovieInfomovie = [[MovieInfo alloc] initWithMovieName:@"Movie" movieID:1];
并将其设置为测试
controller.detailItem = movie;
此外,我在setDetailItem
中添加了一个参数断言:
NSParameterAssert([newDetailItem isKindOfClass:[MovieInfo class]] || [newDetailItem isKindOfClass:[PersonInfo class]] || newDetailItem == nil);
这个断言也失败了。
我在断言调用上面放了两个日志语句:
NSLog(@"%@", [newDetailItem class]);
NSLog(@"%@", newDetailItem);
显示:
2012-08-28 08:31:37.574 Popcorn[8006:c07] MovieInfo
2012-08-28 08:31:38.253 Popcorn[8006:c07] <MovieInfo: 0x6daac50>
另外一个编辑:
我在单元测试中设置isKindOfClass
检查之前添加了if ([movie isKindOfClass:[MovieInfo class]]) {
NSLog(@"Yep"); //This passes and prints out
}
controller.detailItem = movie; //calls into the setter and fails.
检查。
{{1}}
答案 0 :(得分:16)
这是因为被测试的类“DetailViewController”不在测试的目标中。我原以为这会以不同的方式表现出来(链接器错误或其他东西),但显然,它只会导致奇怪的行为。将DetailViewController添加到测试目标可以解决问题。
答案 1 :(得分:2)
我怀疑是竞争条件,还是调试和发布配置之间存在差异。这些将导致调试器和常规运行时之间的差异。
首先,确保self.detailItem
不是nil
。这是此类问题的最常见原因。然后尝试使用日志而不是调试器来调试它。如果您确实有竞争条件,那么您也可以考虑使用printf()
而不是NSLog()
进行记录。 printf()
是一种影响性能的方法,可用于进行多线程日志记录。
答案 2 :(得分:2)
我在写作的图书馆里遇到了同样的问题。有趣的是,它在我的iOS测试目标上运行良好,但在Mac测试目标上失败了(有趣!)。
我认为这个问题与类声明中的不匹配有关。该库正在使用.h声明,但单元测试正在查看内部声明。
用一个例子来解释更容易:
/*
* ClassA.h
*/
@interface ClassA () : NSObject
@property (nonatomic, strong, readonly) NSString *someValue1;
@property (nonatomic, strong, readonly) NSString *someValue2;
@property (nonatomic, strong, readonly) NSString *someValue3;
@end
添加到.m
中的属性列表/*
* ClassA.m
*/
@interface ClassA () : NSObject
@property (nonatomic, strong, readwrite) NSString *someValue2;
@property (nonatomic, strong, readwrite) NSDate *date;
@property (nonatomic, strong, readwrite) NSDateFormatter *dateFormatter;
@end
@implementation
// implementation
@end
现在,由于单元测试目标的编译源设置为包含ClassA.m,isKindOfClass:
将返回no,但po
命令和NSStringFromClass([ClassA class])
在调试器中运行时返回您期望的值。
我知道这是一个老帖子,但我希望这很有用,可以节省很多时间。我花了差不多一个小时试图解决这个问题!
答案 3 :(得分:1)
如果您希望始终将所有源文件添加到所有测试目标中,MarkPowell的答案绝对有帮助。
但是,如果您将Application作为测试目标的目标依赖项(如果测试目标中只有测试源文件,而不是项目源文件),那么您遇到了同样的问题:你的类应该在App目标中,而不是测试目标(在我的例子中,它是一个测试助手类!)
答案 4 :(得分:1)
如@stefreak所述,在标准单元测试配置中,测试对象不应包含在单元测试目标中。在这种情况下,如果确实在测试目标中包含了测试对象,则在构建时会将以下类型的消息写入日志:
Class foo is implemented in both <.app path> and <.xctest path>. One of the two will be used. Which one is undefined.
正如前面提到的here,你不应该在两个目标中都包含被测对象。仅将对象放在一个目标中将使用isKindOfClass:
停止意外行为。
此外,我的一位同事发现你需要确保关闭单元测试&#34;运行&#34;建立。根据应用程序,选择&#34; Build&#34;,然后查看单元测试目标,&#34;运行&#34;应该被取消选择。
如果你在Swift中开发,那么你的单元测试文件顶部应该有一个@testable import MyModule
。
答案 5 :(得分:0)
self.detailItem
可以nil
吗?在这种情况下,-isKindOfClass:
的结果为NO
。
答案 6 :(得分:0)
同样的情况发生在我身上。 我最终做了如下比较:
[self.detailItem class] == [ETTWallpaper class]
自
[[self.detailItem class] isKindOfClass:[ETTWallpaper class]]
没有工作,并且总是返回NO,尽管确定它必须返回YES
答案 7 :(得分:0)
我认为目前Xcode 7.0中存在一个错误。我有同样的问题,并检查所有CUT都包含在测试目标中,但我有一个在代码中返回NO
到-[isKindOfClass:]
,但在调试器中返回YES。这种情况发生在模拟器和物理设备中。
我最终检查了-[respondsToSelector:]
以检查我的班级签名。不完美,但允许我通过。
答案 8 :(得分:0)
使用CocoaPods 1.0运行单元测试时遇到同样的问题
(其中SomeClass
位于Pod库中)
我收到以下警告信息:
Class SomeClass is implemented in both </path/to/myapp> and </path/to/myapptest>. One of the two will be used. Which one is undefined.
我的解决方案是将Podfile更新为:
target "MyApp" do
pod 'xxx'
pod 'yyy'
target "MyApp-Tests" do
inherit! :search_paths
end
end
答案 9 :(得分:0)
在此link中找到了解决方案:
我的SomeEntity类包含在测试目标中。构建测试目标还包括将主应用程序作为依赖项,其中还包括SomeEntity。显然,这使Xcode相信有2种不同的类型。
从测试目标中删除SomeEntity,一切顺利!