什么是真正的单元测试?

时间:2015-11-11 09:28:25

标签: javascript angularjs unit-testing jasmine

所以有一段时间我现在一直在思考真正的单元测试应该包含什么。最好用一个例子来证明这一点,这是我想测试的角度服务:

function stringUtils() {
    return {  
        splitFilterString: splitFilterString
    } 

    function splitFilterString (filterString) {
        return filterString.split(':');
    }
}

我一直在想我的两种方法中哪一种最能描述一种真实的" splitFilterString的单元测试。 (这些例子是用茉莉花写的)

1测试String.prototype.split已被调用。

你不测试任何真实的"这样的示例,您只需测试该函数实际调用String.prototype.split并返回该函数返回的内容。到目前为止,这一直是我的测试方式,因为你不测试"外部" API用于执行他们(应该)正在做的事情。

    it('should call split with ":" as an argument and return whatever split returns', function () {
        var filterString = 'foo:bar';
        spyOn(String.prototype, 'split').and.returnValue('foo');
        expect(stringUtils.splitFilterString(filterString)).toBe('foo');
        expect(String.prototype.split).toHaveBeenCalledWith(':');
    });

2测试函数的实际预期输出。

我也喜欢这种方法,因为您测试实际输入/输出如何使用该函数。在缺点方面,你也在这里间接测试String.prototype.split,你正在测试它是否真的按照它所说的那样进行测试。

    it('should return the correct output', function () {
        expect(stringUtils.splitFilterString('foo:bar')).toEqual(['foo', 'bar']);
        expect(stringUtils.splitFilterString('foobar')).toEqual(['foobar']);
    });

1 个答案:

答案 0 :(得分:2)

在第一个例子中,您将测试与实现相结合,这是主要区别。

如果您发现要使用superFastSplit,那么这可能会妨碍您,因为您需要更改代码您的测试。
所以在这种情况下,测试并没有提供真正的价值,因为当你想要重构时它会阻止你:"我想重构那部分代码,但那些该死的测试意味着我必须做所有的事情两次"!

在第二个示例中,您正在测试行为,因此您的代码将允许您使用superFastSplit,因为您对如何获得结果不感兴趣,您感兴趣的是结果在实现中是一致的。< / p>

编辑 OP评论后

在外部API的情况下,我仍然会遵循“不要伤害我未来的自我/同事”#34;路径,所以我会做最简单的事情,IMHO是使用模拟外部API的模块,如下所示:

nock('http://external.api.com')
  .get('/end/point')
  .reply(200);

当然,你必须要小心并且不要尝试覆盖太多的场景,因为你基本上决定外部API会返回什么,所以我想我会在这里测试ok和nok场景,并涵盖集成测试中的所有细节。

nock所涵盖的内容是:

  

Nock通过覆盖Node的http.request函数来工作。此外,它也会覆盖http.ClientRequest,以覆盖直接使用它的模块。

您可以随时测试API调用在代码中的任何副作用,但我觉得在应用TDD时更难以遵循这种方法。