问题在 PHP 中,但适用于使用 xUnit 框架的任何语言。
我想要一个 mock,需要 140 次调用 jump 方法。
我需要验证,至少一次有一个以 500 作为参数的调用。
我不在乎是否所有调用都是 500,但我至少需要一个调用了 500 的调用。
$mock = $this->getMock('Trampoline', ['jump']);
$mock->expects($this->atLeastOnce())
->method('jump')
->with($this->equalTo(500))
->will($this->returnValue(true));
$sportsman->setTramploine($mock);
$sportsman->jumpToRandomHeights($times = 140); // this calls Trampoline->jump
// I need to verify the sportsman had jumped
// to the height of 500 at least once out of the 140 jumps he is performing
在当前代码中,测试在第一次调用 jump 后失败,因为第一次调用的值不同于 500,这意味着 atLestOnce 这里只是表示应该调用该方法,而不是在其他调用中以特定值调用它。
缺少的信息是在 with 中使用回调。感谢 edorian 在下面的回答,结果是这样的:
$testPassed = false;
$checkMinHeight = function ($arg) use(&$testPassed)
{
if($arg === 500)
$testPassed = true;
// return true for the mock object to consider the input valid
return true;
}
$mock = $this->getMock('Trampoline', ['jump'])
->expects($this->atLeastOnce())
->method('jump')
->with($checkMinHeight)
->will($this->returnValue(true));
$sportsman->setTramploine($mock);
$sportsman->jumpToRandomHeights($times = 1000); // this calls Trampoline->jump
// I need to verify the sportsman had jumped
// to the height of 500 at least once out of the 1000 jumps he is performing
$this->assertTrue($testPassed, "Sportsman was expected to
jump 500m at least once");
最佳答案
你可以,但我能想到的使用 PHPUnits 模拟 API 的最佳实现看起来仍然很令人毛骨悚然。
另一种更易读的解决方法是创建您自己的 Trampoline 子类并在那里实现它。
假设这个类:
<?php
class FancyMocking {
function doThing($value) { }
}
并且我们有 $x 调用,其中一个必须有 $value > 200:
<?php
class FancyMockingTest extends PHPUnit_Framework_TestCase {
public function testAtLeastOfMy200CallsShouldHaveAValueGreaterThan500() {
$maxInvocations = 200;
$mock = $this->getMock('FancyMocking');
$mock->expects($this->exactly($maxInvocations))
->method('doThing')
->with($this->callback(function ($value) use ($maxInvocations) {
static $invocationCount = 0;
static $maxValue = 0;
$maxValue = max($value, $maxValue);
/* The assertion function will be called twice by PHPUnit due to implementation details, so the *2 is a hack for now */
if (++$invocationCount == $maxInvocations * 2) {
$this->assertGreaterThan(200, $maxValue, 'in 500 tries the max value didn\'t to over 200');
}
return true;
}))
->will($this->returnCallback(function ($value) {
return $value >= 200;
}));
for($i = $maxInvocations - 2; $i; --$i) {
$mock->doThing(50);
}
var_dump($mock->doThing(250));
var_dump($mock->doThing(50));
}
}
这将产生:
PHPUnit 3.7.9 by Sebastian Bergmann.
.bool(true)
bool(false)
Time: 0 seconds, Memory: 2.75Mb
OK (1 test, 2 assertions)
意味着 250 的调用返回 true 并且整个测试用例有效。
为了让它失败,我们将 var_dump($mock->doThing(250)); 更改为 var_dump($mock->doThing(70)); 并运行再次:
PHPUnit 3.7.9 by Sebastian Bergmann.
Fbool(false)
Time: 0 seconds, Memory: 2.75Mb
There was 1 failure:
1) FancyMockingTest::testAtLeastOfMy200CallsShouldHaveAValueGreaterThan500
Expectation failed for method name is equal to <string:doThing> when invoked 200 time(s)
in 500 tries the max value didn't to over 200
Failed asserting that 70 is greater than 200.
.../FancyMockingTest.php:29
FAILURES!
Tests: 1, Assertions: 1, Failures: 1.
不使用 PHPUnits 模拟 API 的解决方案类似于
class FancyMockingFakeImplementation extends FancyMocking,使用它代替模拟并在那里编写自定义逻辑。
关于php - 用具体值模拟 atLeastOnce,其余的不重要,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13550914/
是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou
假设我在Store的模型中有这个非常简单的方法:defgeocode_addressloc=Store.geocode(address)self.lat=loc.latself.lng=loc.lngend如果我想编写一些不受地理编码服务影响的测试脚本,这些脚本可能已关闭、有限制或取决于我的互联网连接,我该如何模拟地理编码服务?如果我可以将地理编码对象传递到该方法中,那将很容易,但我不知道在这种情况下该怎么做。谢谢!特里斯坦 最佳答案 使用内置模拟和stub的rspecs,你可以做这样的事情:setupdo@subject=MyCl
在ruby中,你可以这样做:classThingpublicdeff1puts"f1"endprivatedeff2puts"f2"endpublicdeff3puts"f3"endprivatedeff4puts"f4"endend现在f1和f3是公共(public)的,f2和f4是私有(private)的。内部发生了什么,允许您调用一个类方法,然后更改方法定义?我怎样才能实现相同的功能(表面上是创建我自己的java之类的注释)例如...classThingfundeff1puts"hey"endnotfundeff2puts"hey"endendfun和notfun将更改以下函数定
我有一个gem,它有一个根据Rails.env的不同行为的方法:defself.envifdefined?(Rails)Rails.envelsif...现在我想编写一个规范来测试这个代码路径。目前我是这样做的:Kernel.const_set(:Rails,nil)Rails.should_receive(:env).and_return('production')...没关系,只是感觉很丑。另一种方法是在spec_helper中声明:moduleRails;end而且效果也很好。但也许有更好的方法?理想情况下,这应该有效:rails=double('Rails')rails.sho
我有一个rspec模拟对象,一个值赋给了属性。我正在努力在我的rspec测试中满足这种期望。只是想知道语法是什么?代码:defcreate@new_campaign=AdCampaign.new(params[:new_campaign])@new_campaign.creationDate="#{Time.now.year}/#{Time.now.mon}/#{Time.now.day}"if@new_campaign.saveflash[:status]="Success"elseflash[:status]="Failed"endend测试it"shouldabletocreat
我正在尝试测试命令行工具的输出。如何使用rspec来“伪造”命令行调用?执行以下操作不起作用:it"shouldcallthecommandlineandreturn'text'"do@p=Pig.new@p.should_receive(:run).with('my_command_line_tool_call').and_return('resulttext')end如何创建stub? 最佳答案 使用newmessageexpectationsyntax:规范/虚拟规范.rbrequire"dummy"describeDummy
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭9年前。我来自C、php和bash背景,很容易学习,因为它们都有相同的C结构,我可以将其与我已经知道的联系起来。然后2年前我学了Python并且学得很好,Python对我来说比Ruby更容易学。然后从去年开始,我一直在尝试学习Ruby,然后是Rails,我承认,直到现在我还是学不会,讽刺的是那些打着简单易学的烙印,但是对于我这样一个老练的程序员来说,我只是无法将它
我的感觉是Camping和Sinatra之间的差异不是很大,您可以安全地选择其中任何一个并且没问题。但我想问问Ruby专家,这是不是真的。Sinatra和Camping微框架之间实际上有什么重要区别吗?您将如何决定使用哪一个? 最佳答案 我知道的唯一显着区别是Camping像Rails一样基于MVC模式,并且与ActiveRecord耦合。Sinatra更加不可知。Camping也不再维护,而Sinatra正在积极开发中。仅这一点就足以让我们先看看Sinatra。编辑:感谢Philippe的更正,很高兴听到Camping的开发正在进
我有一个或多或少这样的场景classAdefinitialize(&block)b=B.new(&block)endend我正在对A类进行单元测试,我想知道B#new是否正在接收传递给A#new的block。我使用Mocha作为模拟框架。这可能吗? 最佳答案 我用Mocha和RSpec都试过了,虽然我可以通过测试,但行为不正确。从我的实验中,我得出结论,验证block是否已通过是不可能的。问题:为什么要传递一个block作为参数?block将用于什么目的?什么时候调用?也许这确实是您应该用类似的东西测试的行为:classBlockP
下面两个语句除了编码风格有区别吗?/regex/=~"some_string_with_regex""some_string_with_regex"=~/regex/ 最佳答案 是的,有区别。正如在http://www.ruby-doc.org/core/classes/Regexp.html#M001232中提到的If=~isusedwitharegexpliteralwithnamedcaptures,capturedstrings(ornil)isassignedtolocalvariablesnamedbythecaptur