php 调用其他需要模拟的类方法的phpunit测试方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18264647/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 17:15:06  来源:igfitidea点击:

phpunit testing method that calls other class methods which need mock

phpphpunit

提问by greg

I'm trying to create a pretty standard unit test where I call a method and assert it's response, however the method I'm testing calls another method inside the same class which does a little bit of heavy lifting.

我正在尝试创建一个非常标准的单元测试,我在其中调用一个方法并断言它的响应,但是我正在测试的方法调用同一个类中的另一个方法,该方法做了一些繁重的工作。

I want to mock that one method but still execute the method I'm testing as is, only with the mocked value returned from the call to the other method.

我想模拟那个方法,但仍按原样执行我正在测试的方法,仅使用从调用另一个方法返回的模拟值。

I've dumbed down the example to make it as simple as possible.

我已经简化了这个例子,使其尽可能简单。

class MyClass
{

    // I want to test this method, but mock the handleValue method to always return a set value.

    public function testMethod($arg)
    {

        $value = $arg->getValue();

        $this->handleValue($value);

    }


    // This method needs to be mocked to always return a set value.

    public function handleValue($value)
    {

        // Do a bunch of stuff...
        $value += 20;

        return $value;

    }

}

My attempt at writing the tests.

我尝试编写测试。

class MyClassTest extends \PHPUnit_Framework_TestCase
{


    public function testTheTestMethod()
    {

        // mock the object that is passed in as an arg
        $arg = $this->getMockBuilder('SomeEntity')->getMock();
        $arg->expects($this->any())
            ->method('getValue')
            ->will($this->returnValue(10));

        // test handle document()
        $myClass = new MyClass();

        $result = $myClass->testMethod($arg);

        // assert result is the correct
        $this->assertEquals($result, 50);

    }

}

I have tried mocking the MyClass object, but when I do that and call the testMethod it always returns null. I need a way to mock the one method but leave the rest of the object intact.

我曾尝试模拟 MyClass 对象,但是当我这样做并调用 testMethod 时,它总是返回 null。我需要一种方法来模拟一个方法,但保持对象的其余部分完好无损。

回答by Schleis

You can mock the class that you are testing and specify the method that you want to mock.

您可以模拟要测试的类并指定要模拟的方法。

$mock = $this->getMockBuilder('MyClass')
    ->setMethods(array('handleValue'))
    ->getMock();

$mock->expects($this->once())
    ->method('handleValue')
    ->will($this->returnValue(23)) //Whatever value you want to return

However, IMO this is not the best idea for your tests.Testing like this will make refactoring much more difficult. You are specifying the implementation of the class rather than the behavior that the class is supposed to have. If handleValueis doing a lot of complicated work that makes testing difficult, consider moving the logic into a separate class and injecting that into your class. Then you can create a mock of that class and pass it in to testMethod. Doing so will give you the added advantage of making MyClassmore extensible if handleValueneeds to adapt its behavior.

但是,IMO 这不是您测试的最佳主意。像这样的测试将使重构变得更加困难。您正在指定类的实现,而不是类应该具有的行为。如果handleValue正在做很多使测试变得困难的复杂工作,请考虑将逻辑移到一个单独的类中并将其注入到您的类中。然后您可以创建该类的模拟并将其传递给testMethod. MyClass如果handleValue需要调整其行为,这样做将为您提供额外的优势,即使其更具可扩展性。

http://www.oodesign.com/strategy-pattern.html

http://www.oodesign.com/strategy-pattern.html

As a general rule, you should not mock the system that you are testing.

作为一般规则,您不应模拟您正在测试的系统。

回答by greg

You can specify which methods to mock (partial mock) with setMethods():

您可以指定要模拟(部分模拟)的方法setMethods()

 // Let's do a `partial mock` of the object. By passing in an array of methods to `setMethods`
 // we are telling PHPUnit to only mock the methods we specify, in this case `handleValue()`.

$csc = $this->getMockBuilder('Lightmaker\CloudSearchBundle\Controller\CloudSearchController')
             ->setConstructorArgs($constructor)
             ->setMethods(array('handleValue'))
             ->getMock();

 // Tell the `handleValue` method to return 'bla'
 $csc->expects($this->any())
     ->method('handleValue')
     ->with('bla');

Any other methods in the class not specified in the array you give setMethods()will be executed as is. If you do notuse setMethodsall methods will return NULLunless you specifically set them.

未在您提供的数组中指定的类中的任何其他方法setMethods()将按原样执行。如果您使用setMethods所有方法,NULL除非您专门设置它们,否则将返回。