单元测试/函数监视

一个用于phpunit的测试工具,帮助测试全局定义的函数

v1.0.0 2015-02-27 21:53 UTC

This package is not auto-updated.

Last update: 2024-09-14 15:58:10 UTC


README

有时候你想要对全局或本地PHP方法进行单元测试,尤其是在与包含大量全局定义函数的包(如Wordpress)一起工作时。

灵感来源于javascript测试模块:https://github.com/jasmine/jasmine

安装

  • composer require --dev unit-testing/function-spy:dev-master
  • 或者,在您的composer.json中添加模块,如下所示:"require-dev": { "unit-testing/function-spy": "dev-master" }然后运行composer update

监视器

Spy类是一个静态容器,它启动一个Registry实例。它有一个定义的静态方法instance来实例化或获取绑定实例的Registry。所有其他静态调用都被转发到Registry实例。

您只有在尝试模拟要测试的函数或类方法时才需要使用静态方法

<?php namespace MyNamespace;

class TestCase extends \PHPUnit_Framework_TestCase {
	use \UnitTesting\FunctionSpy\SpyTrait;

	function test_functionOrMethod_CanBeSpied()
	{
		function_under_test('foo');
		$this->assertFunctionLastCalledWith('function_under_test', array('foo'));

		$instance = new FakeInstanceThatHasMethodWhichCallsFunctionUnderTest();
		$instance->methodWhichCallsFunctionUnderTest('bar');
		$this->assertFunctionLastCalledWith('function_under_test', array('bar'));
	}
}

function function_under_test()
{
	\UnitTesting\FunctionSpy\Spy::function_under_test();
}

class FakeInstanceThatHasMethodWhichCallsFunctionUnderTest {

	function methodWhichCallsFunctionUnderTest($param)
	{
		function_under_test($param);
	}
}

注册表

Registry负责记录所有监视到的函数调用及其相应的参数。它还有一些函数用于执行更深入的分析。

  • getRecorders返回一个包含所有被监视函数的数组。数组中的每个键是一个函数名,其值是一个Recorder实例。
  • getRecorder($name)获取匹配的函数调用的Recorder实例或如果没有调用该函数则返回null。
  • flushRecorders显式清空记录器数组
  • setFunctionResult($name, $result)为函数创建一个Recoder实例(如果尚未创建)并设置该函数的返回值
  • 为了方便,Registry实例实现了ArrayAccess,以便访问/实例化监视器或设置其结果。

记录器

  • getCalls获取所有调用及其相应的参数列表
  • wasCalled检查方法是否被调用
  • wasCalledWith检查方法是否以特定的参数列表被调用
  • wasLastCalledWith检查方法的最后一次调用是否与特定的参数列表匹配

SpyTrait

SpyTrait是一个简单的特质,可以被任何PHPUnit测试用例使用来自动设置和清空Registry。只需几行代码,它就会实例化Registry并在测试用例上设置一个$spy属性,以便在测试中轻松访问。它还扩展了测试用例,添加了一些断言方法来帮助检查全局函数是否被调用。

  • protected initSpy:从您的setUp()方法中调用此方法来初始化监视器和设置$spy成员
  • protected flushSpy:从您的tearDown()方法中调用此方法来清除所有对监视器的调用,以便在每个测试之间清空所有调用。
  • assertFunctionNotCalled:确保全局函数没有被调用
  • assertFunctionNotCalledWith:确保全局函数没有以特定参数被调用
  • assertFunctionCalledWith:确保全局函数以特定参数被调用
  • assertFunctionLastCalledWith:确保全局函数最近一次以特定参数被调用

注释示例

假设有一个你继承并需要与之工作的方法 doSomethting。你想要确保它以正确的参数在应该调用的时候被调用。你的类 MyNamespace\MyClass 中有一个方法 doFoo,它会根据条件调用 doSomething 函数并返回其结果。

测试主题

<?php namespace MyNamespace;
class MyClass {
	public function doFoo($param1, $param2)
	{
		if ($param1 == 'bar')
		{
			return doSomething($param1, $params);
		}
	}
}

测试用例

<?php namespace MyNamespace;
class MyTest extends \PHPUnit_Framework_TestCase {
	// Use the trait
	use \UnitTesting\FunctionSpy\SpyTrait;

	protected function setUp()
	{
		// init the spy
		$this->initSpy();
	}
	protected function tearDown()
	{
		// flush the spy so we can reset the calls after every test
		$this->flushSpy();
	}

	function test_doFoo_WithBar_CallsDoSomethingWithBar()
	{
		$myClass = new MyClass();

		$myClass->doFoo('bar', 'baz');

		// we've ensured that the doSomething() method has been called with bar and baz
		$this->assertFunctionLastCalledWith('doSomething', array('bar', 'baz'));
	}

	function test_doFoo_WithBar_ReturnsResultOfDoSomething()
	{
		// we'll set the result for the function doSomething() to return "doSomething result"
		$this->spy['doSomething']->setResult('doSomething result');
		// alternatively, you can also just assign set the property:
		// $this->spy['doSomething'] = 'doSomething result';

		$myClass = new MyClass();

		$result = $myClass->doFoo('bar', 'baz');

		// we ensure that the doFoo() method returns the result of doSomething();
		$this->assertEquals('doSomething result', $result);
	}

	function doFoo_WithBaz_NeverCallsDoSomething()
	{
		$myClass = new MyClass();

		$myClass->doFoo('some param which does not call doSomething');

		// ensure that doSomething() is never called
		$this->assertFunctionNotCalled('doSomething');
	}

}

// this is needed because we're overriding the globally defined doSomething within our namespace.
function doSomething()
{
	// the Spy static class allows you to simply call any method name and it will log the call with that name.
	// if you don't explicity pass parameters, it will attempt to guess the passed parameters to this function
	// using debug_backtrace()
	return Spy::doSomething();
}

致谢

其他处理此测试问题的包/引用,并作为参考使用