问题描述
我一直在研究如何添加单元测试覆盖到PHP编写的大型现有代码库。静态和可实例化类中的许多函数调用库或实例化对象以获取到memcache和数据库的连接。它们通常看起来像这样:
I have been looking into how to add unit testing coverage to a large, existing codebase written in PHP. Many functions in both static and instantiable classes make a call to a library or instantiate an object in order to obtain connections to memcache and the database. They typically look something like this:
public function getSomeData() {
$key = "SomeMemcacheKey";
$cache = get_memcache();
$results = $cache->get($key);
if (!$results) {
$database = new DatabaseObject();
$sql = "SELECT * from someDatabase.someTable";
$results = $database->query($sql);
$cache->set($key, $results);
}
return $results;
}
我的同事和我目前正试图通过PHPUnit实现几个我们正在写的新类。我试图找到一种方法来以孤立的方式为我们现有的代码库中的函数创建类似于上面的伪代码,但是未成功的单元测试。
My colleagues and I are currently trying to implement coverage via PHPUnit for a few of the new classes we are writing. I have attempted to find a way to create unit tests in an isolated manner for functions in our existing codebase that resemble the pseudo-code above, but have been unsuccessful.
示例我在PHPUnit文档中看到的都依赖于在类中有一些方法,通过它可以附加一个mock对象,例如:
$ objectBeingTested-> attach($ mockObject);
我看了SimpleUnit,看到了同样的事情,模拟对象通过它的构造函数被传递到类中。这不会为实例化自己的数据库对象的函数留出很多空间。
The examples I've seen in the PHPUnit documentation all rely on having some method in the class by which a mock object can be attached to it, such as:$objectBeingTested->attach($mockObject);
I looked at SimpleUnit, and saw the same thing there, the mock objects were being passed into the class via its constructor. This doesn't leave much room for functions which instantiate their own database objects.
有没有办法模拟这些类型的调用?有没有另一个单元测试框架我们可以使用?或者我们将不得不改变我们将来使用的模式,以便于单元测试?
Is there any way to mock out these sorts of calls? Is there another unit testing framework we can use? Or are we going to have to change the patterns we are using in the future in order to facilitate unit testing?
我想做的是能够交换在运行测试时使用模拟类来完成整个类。例如,DatabaseObject类可以替换为mock类,并且任何时候它在测试期间被实例化,它实际上是模拟版本的实例。
What I'd like to do is be able to swap out an entire class with a mock class when running tests. For instance, the DatabaseObject class could be replaced with a mock class, and any time it's instantiated during a test, it would actually be an instance of the mock version.
已经在我的团队中谈论重构我们的访问数据库和memcache的方法在新的代码,也许使用单例。我想如果我们以这样一种方式编写单例,以便自己的实例可以替换为一个模拟对象,可以帮助...
There has been talk in my team of refactoring our methods of accessing the database and memcache in new code, perhaps using singletons. I suppose that could help if we were to write the singleton in such a way that its own instance of itself could be replaced with a mock object...
这是我的首先进入单元测试。如果我做错了,请说。 :)
This is my first foray into unit testing. If I'm doing it wrong, please say so. :)
感谢。
推荐答案
有时间重构所有的旧代码以使用依赖注入或类似的东西。
In a perfect world, you'd have the time to refactor all your legacy code to use dependency injection or something similar. But in the real world, you often have to deal the hand you've been dealt.
PHPUnit的作者Sebastian Bergmann写了一个,它允许您使用回调和重命名函数覆盖新运算符。这些将允许你在测试期间猴子补丁你的代码,直到你可以重构它更可测试。非常感谢,使用这个功能写的测试越多,您就可以撤消它。
Sebastian Bergmann, the author of PHPUnit, wrote a test helpers extension that allows you to override the new operator with a callback and rename functions. These will allow you to monkey patch your code during testing until you can refactor it to be more testable. Granted, the more tests you write using this, the more work you'll have undoing it.
这篇关于在PHP内部使用模拟对象,实例化自己的对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!