Javascript 如何对只调用其他函数的函数进行单元测试?
我的代码库(遗留)中有一个函数,它具有:Javascript 如何对只调用其他函数的函数进行单元测试?,javascript,unit-testing,Javascript,Unit Testing,我的代码库(遗留)中有一个函数,它具有: function test() { method1("#input a") method2("test") method3(1,2) } 考虑到它调用其他方法的事实,如何为这类函数编写良好的单元测试?首先,我认为您描述的这种行为甚至不需要进行单元测试。 但是,如果您确实需要检查方法是否使用特定参数(甚至任何参数)调用。 有一种方法可以做到这一点,可以使用类似ShortifyPunit的模拟框架: 按照以下步骤操作: 确保附加到可以模拟的对象的方
function test()
{
method1("#input a")
method2("test")
method3(1,2)
}
考虑到它调用其他
方法的事实,如何为这类函数编写良好的单元测试?首先,我认为您描述的这种行为甚至不需要进行单元测试。
但是,如果您确实需要检查方法是否使用特定参数(甚至任何参数)调用。
有一种方法可以做到这一点,可以使用类似ShortifyPunit的模拟框架:
按照以下步骤操作:
确保附加到可以模拟的对象的方法
将模拟对象注入类并存根方法
您可以验证()方法是使用特定参数调用的
例如,如果您的类正在使用依赖项注入,这对于以下类之类的单元测试至关重要:
class SomeClass {
private $obj;
public function __construct($obj) {
$this->obj = $obj;
}
public function test()
{
$this->obj->method1("#input a")
$this->obj->method2("test")
$this->obj->method3(1,2)
}
}
您可以编写如下的单元测试:
public function testMethodCalled()
{
$mockedObj = ShortifyPunit::mock('object');
$class = new SomeClass($mockedObj);
// Stub the methods so you could verify they were called
ShortifyPunit::when($mockedObj)->method1(anything())->returns(1);
ShortifyPunit::when($mockedObj)->method2(anything())->returns(2);
ShortifyPunit::when($mockedObj)->method3(anything(), anything())->returns(3);
$class->test(); // run test() method
// Verify it was called
$this->assertTrue(ShortifyPunit::verify($mockedObj)->method1(anything())->calledTimes(1));
$this->assertTrue(ShortifyPunit::verify($mockedObj)->method2(anything())->calledTimes(1));
$this->assertTrue(ShortifyPunit::verify($mockedObj)->method3(anything(), anything())->calledTimes(1));
}
考虑到它调用其他方法的事实,
(…)
不管它叫什么。从消费者(呼叫者)的角度来看,最终结果非常重要。你总是测试最终结果。调用其他一些方法的事实与实现细节无关(在大多数情况下)
我建议做一个简单的练习——将method1
、method2
和method3
主体内联到test
方法中。您在确定要测试的内容时会遇到问题吗
您希望测试公共契约或可观察行为—方法调用的最终结果对调用它的人可见(许多不同的参与者可能会调用您的方法—程序的其他部分、单元测试或系统用户;每个人都应该经历相同的可观察行为)
现在,回到多次提到的“最终结果”/“方法的可观察行为”。它可以是三件事之一:
- 返回值(您的方法不这样做)
- 调用第三方组件(您的方法可能正在这样做)
- 系统内部状态的变化(您的方法似乎正在这样做)
您需要确定最终结果并进行测试。这是一个非常好的问题,我也为此挣扎了很长时间。在本例中,您有一个要测试的函数test
,但该函数有依赖项-method1-3
。
基本上有两种方法-
保持代码不变,只需测试test
功能即可
将依赖项作为参数传递-
范例-
function test(method1, method2, method3) {
method1("#input a")
method2("test")
method3(1,2)
}
第二种方法将为您提供模拟方法1、2和3的灵活性
它也可能是案例一和案例二的混合,其中一些方法直接从全局范围使用,一些作为参数传递
现在唯一的问题是理解什么时候使用什么。这里有一些提示-
对于案例一
依赖项是简单的同步函数。在JS中,异步函数通常会做一些与IO相关的工作,或者有时会进行非常昂贵的计算,这两项工作都不应该妨碍对test
函数的测试
它接受输入参数并返回输出李>
它们不会在应用程序中的任何位置改变任何状态或发送任何事件
对于所有其他情况,您都希望将依赖项作为参数传递。例如,在本例中,看起来method1
和method2
正在执行一些DOM操作,这意味着它们应该被注入和模拟,因为asmethod3
看起来非常简单,可以从全局范围使用
function (d) {
d.method1("#input a")
d.method2("test")
method3(1,2)
}
如果依赖项太多,可以传递包含所有依赖项的对象 我的观点是,对于这样的函数,不需要单元测试,只测试内部方法就足够了。真的足够了吗?更改此函数内的调用顺序将改变其行为。一般来说,您的建议很好,但至少在JS中,您可以不使用对象直接模拟函数。