草庐IT

PHPUnit:模拟后包含类

coder 2024-04-05 原文

我很乐意编写单元测试,但是当我一起运行它们时它们会发生冲突。我正在测试这个类:

class MyClass {

    public function sayHello() {
        return 'Hello world';
    }
}

使用这个测试。所有测试的结构如下:

class MyClassTest extends PHPUnit_Framework_TestCase {
    private $subject;

    public static function setUpBeforeClass() {
        require_once('path/to/MyClass.php');
    }

    public function setUp() {
        $this->subject = new MyClass();
    }

    public function testSayHello() {
        $this->assertEquals('Hello world', $this->subject->sayHello());
    }
}

MyClassTest 本身运行良好。但是 PHPUnit 会崩溃,因为我重新声明了类,如果另一个测试模拟了 MyClass 并且碰巧先运行了:

class Inject {

    private $dependency;

    public function __construct(MyClass $myClass) {
        $this->dependency = $myClass;
    }

    public function printGreetings() {
        return $this->dependency->sayHello();
    }
}

class InjectTest extends PHPUnit_Framework_TestCase {

    public function testPrintGreetings() {
        $myClassMock = $this
            ->getMockBuilder('MyClass')
            ->setMethods(array('sayHello'))
            ->getMock();
        $myClassMock
            ->expects($this->once())
            ->method('sayHello')
            ->will($this->returnValue(TRUE));

        $subject = new Inject($myClassMock);

        $this->assertEquals('Hello world', $subject->printGreetings());
    }
}

我确实使用 bootstrap.php 来伪造一些尚未重构的全局函数。

我没有自动加载器并且不想处理隔离每个测试,因为它需要永远。我尝试在测试 1 和 2 的文档 block 中插入组合 @runTestsInSeparateProcesses@preserveGlobalState enabled/disabled,我仍然遇到相同的错误。

最佳答案

要了解此行为,您需要了解 PHPUnit 的工作原理。 getMockBuilder()->getMock() , 为模拟类动态创建以下代码:

class Mock_MyClass_2568ab4c extends MyClass implements PHPUnit_Framework_MockObject_MockObject
{
    private static $__phpunit_staticInvocationMocker;
    private $__phpunit_invocationMocker;

    public function __clone()
    {
        $this->__phpunit_invocationMocker = clone $this->__phpunit_getInvocationMocker();
    }

    public function sayHello()
    {
        $arguments = array();
        $count     = func_num_args();

        if ($count > 0) {
            $_arguments = func_get_ ... 

     # more lines follow ...

如果MyClass此时尚未加载,它添加了以下虚拟声明:

class MyClass
{
}

此代码随后将使用 eval() 进行解析(!).

因为 PHPUnit 将执行 InjectTest 之前 MyClassTest ,这意味着模拟生成器将定义虚拟类和 MyClass MyClassTest::setUpBeforeClass 时已经定义会被叫到。这就是错误的原因。我希望我能解释一下。否则,请深入研究 PHPUnit 的代码。


解决方案:

删除 setUpBeforeClass()方法并把require_once测试之上的声明。 setUpBeforeClass()并不意味着包括类(class)。引用docs .

顺便说一句,有 require_once在顶部将起作用,因为 PHPUnit 将在 开始第一个测试之前包含每个测试文件。

测试/MyClassTest.php

require_once __DIR__ . '/../src/MyClass.php';

class MyClassTest extends PHPUnit_Framework_TestCase {
    private $subject;

    public function setUp() {
        $this->subject = new MyClass();
    }

    public function testSayHello() {
        $this->assertEquals('Hello world', $this->subject->sayHello());
    }
}

测试/InjectTest.php

require_once __DIR__ . '/../src/Inject.php';

class InjectTest extends PHPUnit_Framework_TestCase {

    public function testPrintGreetings() {
        $myClassMock = $this
            ->getMockBuilder('MyClass')
            ->setMethods(array('sayHello'))
            ->getMock();
        $myClassMock
            ->expects($this->once())
            ->method('sayHello')
            ->will($this->returnValue(TRUE));

        $subject = new Inject($myClassMock);

        $this->assertEquals(TRUE, $subject->printGreetings());
    }   
}

关于PHPUnit:模拟后包含类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25693038/

有关PHPUnit:模拟后包含类的更多相关文章

  1. ruby - 检查 "command"的输出应该包含 NilClass 的意外崩溃 - 2

    为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar

  2. ruby - 如何模拟 Net::HTTP::Post? - 2

    是的,我知道最好使用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

  3. ruby - 检查字符串是否包含散列中的任何键并返回它包含的键的值 - 2

    我有一个包含多个键的散列和一个字符串,该字符串不包含散列中的任何键或包含一个键。h={"k1"=>"v1","k2"=>"v2","k3"=>"v3"}s="thisisanexamplestringthatmightoccurwithakeysomewhereinthestringk1(withspecialcharacterslike(^&*$#@!^&&*))"检查s是否包含h中的任何键的最佳方法是什么,如果包含,则返回它包含的键的值?例如,对于上面的h和s的例子,输出应该是v1。编辑:只有字符串是用户定义的。哈希将始终相同。 最佳答案

  4. ruby-on-rails - 使用包含多个关联和单独的条件 - 2

    我的Gallery模型中有以下查询:media_items.includes(:photo,:video).rank(:position_in_gallery)我的图库模型有_许多媒体项,每个都有一个照片或视频关联。到目前为止,一切正常。它返回所有media_items包括它们的photo或video关联,由media_item的position_in_gallery属性排序。但是我现在需要将此查询返回的照片限制为仅具有is_processing属性的照片,即nil。是否可以进行相同的查询,但条件是返回的照片等同于:.where(photo:'photo.is_processingIS

  5. ruby-on-rails - 在这种情况下我如何模拟一个对象?没有明显的方法可以用模拟替换对象 - 2

    假设我在Store的模型中有这个非常简单的方法:defgeocode_addressloc=Store.geocode(address)self.lat=loc.latself.lng=loc.lngend如果我想编写一些不受地理编码服务影响的测试脚本,这些脚本可能已关闭、有限制或取决于我的互联网连接,我该如何模拟地理编码服务?如果我可以将地理编码对象传递到该方法中,那将很容易,但我不知道在这种情况下该怎么做。谢谢!特里斯坦 最佳答案 使用内置模拟和stub的rspecs,你可以做这样的事情:setupdo@subject=MyCl

  6. ruby - 我怎样才能只写一次 "Text"并同时检查 path_info 是否包含 'A' ? - 2

    -if!request.path_info.include?'A'%{:id=>'A'}"Text"-else"Text"“文本”写了两次。我怎样才能只写一次并同时检查path_info是否包含“A”? 最佳答案 有两种方法可以做到这一点。使用部分,或使用content_forblock:如果“文本”较长,或者是一个重要的子树,您可以将其提取到一个部分。这会使您的代码变干一点。在给出的示例中,这似乎有点矫枉过正。在这种情况下更好的方法是使用content_forblock,如下所示:-if!request.path_info.inc

  7. Ruby,使用包含 TK GUI 的 ocra 部署一个 exe - 2

    Ocra无法处理需要“tk”的应用程序require'tk'puts'nope'用奥克拉http://github.com/larsch/ocra不起作用(如链接中的一个问题所述)问题:https://github.com/larsch/ocra/issues/29(Ocra是1.9的"new"rubyscript2exe,本质上它用于将rb脚本部署为可执行文件)唯一的问题似乎是缺少tcl的DLL文件我不认为这是一个问题据我所知,问题是缺少tk的DLL文件如果它们是已知的,则可以在执行ocra时将它们包括在内有没有办法知道tk工作所需的DLL依赖项? 最佳答

  8. ruby - "public/protected/private"方法是如何实现的,我该如何模拟它? - 2

    在ruby中,你可以这样做:classThingpublicdeff1puts"f1"endprivatedeff2puts"f2"endpublicdeff3puts"f3"endprivatedeff4puts"f4"endend现在f1和f3是公共(public)的,f2和f4是私有(private)的。内部发生了什么,允许您调用一个类方法,然后更改方法定义?我怎样才能实现相同的功能(表面上是创建我自己的java之类的注释)例如...classThingfundeff1puts"hey"endnotfundeff2puts"hey"endendfun和notfun将更改以下函数定

  9. ruby - 在 RSpec 中 stub /模拟全局常量 - 2

    我有一个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

  10. ruby - 允许主机名包含下划线的 URI.parse 的替代方法 - 2

    我正在使用DMOZ的listofurltopics,其中包含一些具有包含下划线的主机名的url。例如:608609TheOuterHeaven610InformationandimagegalleryofMcFarlane'sactionfiguresforTrigun,Akira,TenchiMuyoandotherJapaneseSci-Fianimations.611Top/Arts/Animation/Anime/Collectibles/Models_and_Figures/Action_Figures612虽然此url可以在网络浏览器中使用(或者至少在我的浏览器中可以使用:

随机推荐