我在很多地方(包括 Apple Dev Forum)看到,为了测试异步操作,一些开发人员建议获取当前运行循环并让它运行一段时间以强制调用异步 block 。例如
__block id returnedModel = nil;
BOOL result = [binder fetchAndBind:...
successBlock:^(id *model) { returnModel = model; }
errorBlock:nil];
NSDate *loopUntil = [NSDate dateWithTimeIntervalSinceNow:10.0f];
BOOL isModelReturned = (returnedModel != nil);
while (!isModelReturned && [loopUntil timeIntervalSinceNow] > 0)
{
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:loopUntil];
isModelReturned = (returnedModel != nil);
}
上述实现有不同的风格,但概念是相同的。一些正在使用 dispatch_group 等
问题:
Apple 是否有任何关于测试异步操作的文档(我找不到)?
我从非官方来源了解到单元测试是 在他们运行的运行循环中自包含。所以他们不是 应该像上面那样处理。真的吗?这是由 哪里有苹果?
在 Xcode 5.1 中,上述实现或 dispatch_group 导致 EXC_BAD_ACCESS (code=2, address=0xd)。是不是因为单元测试是自包含在自己的线程中的概念,不应该这样对待?
我见过这种方法的问题和副作用,特别是如果该测试中的一个或多个对象被模拟。副作用,例如导致应用程序崩溃,从而无法完成单元测试。例如,Class A 中的一个方法,其公共(public) API 将 NSArray 作为输入,因为测试模拟了一个对象而崩溃,让运行循环继续,然后该对象开始与 交互code>Class A 并且因为它被模拟了,所以它传入了字典! -- 而如果 run loop 没有被强制继续,该对象将在稍后取消模拟并且每个测试都会很开心!
我个人认为没有理由去测试async。有一个以异步方式运行的操作。需要测试的是operation/function,而不是async。
我正在寻找一些引用资料或文档(最好来自 Apple)来清楚地讨论异步单元测试,单元测试的运行循环是否可以强制继续,或者使用 XCTests 测试异步操作的推荐方法是什么.
谢谢!
编辑:
在 Xcode 6 中,XCTest 框架附带了异步测试宏。我把这个问题留在这里供引用。
最佳答案
关于您的示例代码存在一些误解:
首先,如果完成处理程序将在与调用站点执行的线程不同的线程上执行,编译器将创建“未定义行为”的代码。这是由于修改了线程“A”中的变量 returnedModel 并读取了线程“M”中的值。这是一个典型的“数据竞争”,它会产生未定义的行为(请阅读 C 和 C++ 规范中的更多内容)。
__block 修饰符可能 可以缓解这个问题,但我不认为 clang 会在这里采取特殊行动。在最坏的情况下,读取值的线程(主线程)永远不会“看到”通过处理程序执行的值更新,或者读取“垃圾”。
此方法的另一个问题需要更透彻地了解运行循环的实际工作方式。在您的示例中,在最坏的情况下,运行循环的方法 runMode:beforeDate: 只会在超时到期时返回 - 即 10 秒后。它可能只有在此模式下处理了一个事件时才会提前返回——可能与测试代码无关。
简而言之,这种方法并不真正适合完成任务。但其他“口味”可能确实有效。
Q1:没有。
原因可能是,XCTest 实际上相当古老(它只是 SenTest 的另一个名称),并且在它被发明时的代码可能没有像“异步操作”、“ block ”和“完成”这样花哨的东西处理程序”。因此没有针对此任务的内置解决方案。
Q2:我不是很理解这个问题。但我们可能会假设“匹配器”(又名“断言某事”)在测试失败时使用异常。那些需要在主线程上执行,其中有一个由底层测试实现实现的 catch 处理程序。也许 XCTest 不使用异常——但是,其他单元测试库可能确实使用异常——例如“Cedar”。这意味着,如果您在某个队列上执行完成处理程序,并且匹配器抛出异常,则它必须在主线程上执行。 (无赖)。
Q3:可能是异常问题?但我不知道。可能还有别的问题。您可以提供更多信息。
其他“副作用”可能是“竞争条件”或其他问题。但除非你提供更详细的信息,否则我猜 ;)
是否需要“测试异步”实际上取决于您实际测试的是什么:
例如,如果您使用具有完成处理程序的知名第三方网络库,您是否真的想测试该处理程序是否会被调用? (可能不会,因为您不想实际测试网络库)。
但是如果您实现了自己的异步操作并通过完成处理程序报告结果,您实际上可能想要测试是否会调用完成处理程序。
关于ios - 用于异步测试的 XCTest 和 NSRunLoop,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23499801/
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje
我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当
exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby中使用两个参数异步运行exe吗?我已经尝试过ruby命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何rubygems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除
我有一个围绕一些对象的包装类,我想将这些对象用作散列中的键。包装对象和解包装对象应映射到相同的键。一个简单的例子是这样的:classAattr_reader:xdefinitialize(inner)@inner=innerenddefx;@inner.x;enddef==(other)@inner.x==other.xendenda=A.new(o)#oisjustanyobjectthatallowso.xb=A.new(o)h={a=>5}ph[a]#5ph[b]#nil,shouldbe5ph[o]#nil,shouldbe5我试过==、===、eq?并散列所有无济于事。
我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere
Sinatra新手;我正在运行一些rspec测试,但在日志中收到了一堆不需要的噪音。如何消除日志中过多的噪音?我仔细检查了环境是否设置为:test,这意味着记录器级别应设置为WARN而不是DEBUG。spec_helper:require"./app"require"sinatra"require"rspec"require"rack/test"require"database_cleaner"require"factory_girl"set:environment,:testFactoryGirl.definition_file_paths=%w{./factories./test/
我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test
我已经在Sinatra上创建了应用程序,它代表了一个简单的API。我想在生产和开发上进行部署。我想在部署时选择,是开发还是生产,一些方法的逻辑应该改变,这取决于部署类型。是否有任何想法,如何完成以及解决此问题的一些示例。例子:我有代码get'/api/test'doreturn"Itisdev"end但是在部署到生产环境之后我想在运行/api/test之后看到ItisPROD如何实现? 最佳答案 根据SinatraDocumentation:EnvironmentscanbesetthroughtheRACK_ENVenvironm
我已经构建了一些serverspec代码来在多个主机上运行一组测试。问题是当任何测试失败时,测试会在当前主机停止。即使测试失败,我也希望它继续在所有主机上运行。Rakefile:namespace:specdotask:all=>hosts.map{|h|'spec:'+h.split('.')[0]}hosts.eachdo|host|begindesc"Runserverspecto#{host}"RSpec::Core::RakeTask.new(host)do|t|ENV['TARGET_HOST']=hostt.pattern="spec/cfengine3/*_spec.r