Amo*_*Amo 8 testing phpunit unit-testing mocking
我有一个类,它有一个利用PHP的全局file_get_contents函数的方法.我需要在类上测试方法,而不是实际调用全局函数.
我知道我可以使用命名空间来覆盖返回的内容file_get_contents,但是我的测试已经在一个单独的命名空间中,所以我不能简单地将命名空间与类匹配.
这是一些代码:
<?php
namespace MyVendor\MyProject;
class MyClass
{
private $someProperty;
public function __construct($override = '')
{
$this->someProperty = $override;
}
public function myMethod()
{
$request = 'http://example.com';
$response = $this->someMethodUsingGlobals($request);
// Do something with the response..
}
public function someMethodUsingGlobals($url)
{
return json_decode(file_get_contents($url),true)['results'][0];
}
}
Run Code Online (Sandbox Code Playgroud)
<?php
namespace MyProjectTests;
public function test_it_does_something_with_the_response()
{
$sut = new MyClass();
$response = $sut->myMethod();
$this->assertEquals('Some expectation', $response);
}
Run Code Online (Sandbox Code Playgroud)
我需要someMethodUsingGlobals()在类上模拟该方法,但不完全确定如何去做.
最简单,最干净的方法是围绕本机函数创建包装器类。
如果遵循DDD和/或六边形体系结构,则可能会将其放置在“适配器”空间中,并且如果不遵循DDD或十六进制拱形结构,则将其放置在“接触外部世界”的任何类组的旁边。
此包装器是一类类:
<?php
declare( strict_types = 1 );
namespace MyVendor\MyProject\Adapters;
class FileGetContentsWrapper
{
public function fileGetContents( string $filename )
{
return file_get_contents( $filename );
}
}
Run Code Online (Sandbox Code Playgroud)
该类仅使用本机函数,因此无法进行测试。
但是有了它,您只需将“ unesting”“转移”到这种单行代码类,现在您就可以使用其他所有file_get_contents()可测试的地方围绕逻辑(除了文件读取之外)覆盖代码。
您可以这样进行:
例如,您的课程可能会导致以下结果:
<?php
namespace MyVendor\MyProject;
use MyVendor\MyProject\Adapters\FileGetContentsWrapper;
class MyClass
{
private $fileGetContentsWrapper;
public function __construct( FileGetContentsWrapper $fileGetContentsWrapper )
{
$this->fileGetContentsWrapper = $fileGetContentsWrapper;
}
/* ... */
public function someMethodUsingTheWrapper( $url )
{
$contents = $this->fileGetContents( $url );
return json_decode( $contents, true )[ 'results' ][ 0 ];
}
}
Run Code Online (Sandbox Code Playgroud)
您执行以下操作:
例如:
<?php
declare( strict_types = 1 );
namespace MyProjectTests;
use MyVendor\MyProject\Adapters\FileGetContentsWrapper;
use MyVendor\MyProject\MyClass;
use PHPUnit\Framework\TestCase;
class MyClassTest extends TestCase
{
private $fileGetContentsWrapper;
//---------------------------------------------------------------------//
// Setup //
//---------------------------------------------------------------------//
protected function setUp()
{
$this->fileGetContentsWrapper = $this->createMock( FileGetContentsWrapper::class )
parent::setUp();
}
//---------------------------------------------------------------------//
// Tests //
//---------------------------------------------------------------------//
public function testSomeMethodUsingTheWrapper()
{
$sut = $this->getSut();
$someSimulatedJson = '{"results":["abc","xyz"]}';
$this->fileGetContentsWrapper->method( 'fileGetContents' )->willReturn( $someSimulatedJson );
$this->assertEquals( 'xyz', $sut->someMethodUsingGlobals( 'dummy-url' ) );
}
//---------------------------------------------------------------------//
// Private //
//---------------------------------------------------------------------//
private function getSut() : MyClass
{
return new MyClass( $this->fileGetContentsWrapper );
}
}
Run Code Online (Sandbox Code Playgroud)
就这样!希望对您有所帮助!
您可以使用部分模拟对象对其进行归档:您可以仅模拟类的特定方法并执行(和测试)其他方法。
进一步参考这里
例如,假设您修改后的类:
<?php
namespace Acme\DemoBundle\Service;
class MyClass {
public function myMethod()
{
$request = 'http://domain.com';
$response = $this->someMethodUsingGlobals($request);
// Do something with the response..
return $response;
}
public function someMethodUsingGlobals($url)
{
return json_decode(file_get_contents($url),true)['results'][0];
}
}
Run Code Online (Sandbox Code Playgroud)
您可以使用以下测试类进行测试:
<?php
namespace Acme\DemoBundle\Tests;
class MyProjectTest extends \PHPUnit_Framework_TestCase
{
public function test_it_does_something_with_the_response()
{
$sut = $this->getMock('Acme\DemoBundle\Service\MyClass', array('someMethodUsingGlobals') );
// Set up the expectation for the someMethodUsingGlobals() method
// to be called only once and with the string 'http://domain.com'
// as its parameter.
$sut->expects($this->once())
->method('someMethodUsingGlobals')
->with($this->equalTo('http://domain.com'))
->willReturn('Some expectation');
$response = $sut->myMethod();
$this->assertEquals('Some expectation', $response);
}
}
Run Code Online (Sandbox Code Playgroud)
因此该方法 someMethodUsingGlobals不会执行并返回模拟定义中定义的值。该方法myMethod使用模拟函数执行和处理。
希望这有帮助
| 归档时间: |
|
| 查看次数: |
5924 次 |
| 最近记录: |