2017-03-16 52 views
0

我有一个类可以加载图像,关闭它或重命名它(至少现在,将来会有更多的操作与打开的文件)。测试有状态类

我用Facade模式实现了它(我认为是这样)。

当我试图为它编写测试时,我很快注意到我需要用不同的前提条件测试它(例如,在调用某种方法之前加载图像时)。而且,当我添加新的操作时,测试的数量非常巨大,而且会迅速增长。据我所知,这些不是单元测试,而是端到端测试。

我是TDD的新手,有谁能告诉我有这样复杂的测试是否正常吗?

我期待我的班太多责任的答案,还是让我们想想办法:

// pseudo-code 

// #1 - my way 
function onRenameButtonClick(newName) { 
    imageFacade.rename(newName) 
} 

// #2 - the other way 
function onRenameButtonClick(newName) { 
    if (imageController.isOpened()) { 
    imageRenamer.rename(imageController.image, newName) 
    } 
} 

最终我还是需要测试正确的行为#2,它仍然会涉及使用不同的前提条件。

你如何处理这种情况?这是正常的还是我做错了什么?

P. S.这里是我的门面类的骨架,请注意,在config中有纯函数,它们实际工作,并且actions正在拼接这些纯函数并根据状态触发事件。

function makeImageWTF(loader, renamer) { 
    return { 
    state: { 
     image: null, 
     filePath: null, 
     isLoading: false 
    }, 
    config: { 
     loader, 
     renamer 
    }, 
    triggers: { 
     opening: new Bus(), 
     opened: new Bus(), 
     closed: new Bus(), 
     renamed: new Bus(), 
     error: new Bus() 
    }, 
    actions: { 
     open: function(path) {}, 
     close: function() {}, 
     rename: function(newName) {} 
    } 
    } 
} 

这里是测试

骨架
describe('ImageWTF', function() { 
    describe('initial state', function() { 
    it('should be that', function() { 
     var wtf = makeImageWTF() 
     assert.deepEqual({ 
     image: null, 
     filePath: null, 
     isLoading: false, 
     }, wtf.state) 
    }) 
    }) 

    describe('#open(path)', function() { 
    it('sets isLoading') 
    it('calls config.loader with path') 
    it('sets image, fileName') 
    it('triggers loading, loaded or error') 
    it('clears isLoading') 
    }) 

    describe('#close()', function() { 
    describe('when image is opened', function() { 
     it('resets image') 
     it('triggers closed') 
    }) 

    describe('when image is NOT opened', function() { 
     it('triggers error') 
    })  
    }) 

    describe('#rename()', function() { 
    describe('when image is opened', function() { 
     it('calls config.renamer with oldName and newName') 
     it('sets fileName') 
     it('triggers renamed') 
    }) 

    describe('when image is NOT opened', function() { 
     it('triggers error') 
    }) 
    }) 
}) 

回答

0

(单位)测试就像是生产代码 - 他们可以变得很复杂。但是,目标当然应该尽可能简单。

如果你还没有测试你的代码,我建议你开始写测试来覆盖最重要的用例。一旦你有适当的工作,你可以重构它们。但对我来说,主要关注的是如何进行测试,您将会学到很多东西。

如果他们从一开始就不是“单元测试”,我就不会太在意,只需将其更改为适合您的应用程序。

尽量不要将测试与生产代码结合起来,因为您希望能够灵活地重构生产代码而不必同时更改测试(当然还有其他方法)。对我来说单元测试实际上就是让它更容易,更快地改变和重构代码。他们不会捕捉到应用程序中的所有错误或行为 - 因为您还需要关注其他类型的测试。