我正在尝试测试角度服务,该$document服务通过使用茉莉花服务对DOM进行一些操作。假设它只是将一些指令附加到<body>元素上。
$document
<body>
这样的服务可能看起来像
(function(module) { module.service('myService', [ '$document', function($document) { this.doTheJob = function() { $document.find('body').append('<my-directive></my directive>'); }; } ]); })(angular.module('my-app'));
我想这样测试
describe('Sample test' function() { var myService; var mockDoc; beforeEach(function() { module('my-app'); // Initialize mock somehow. Below won't work indeed, it just shows the intent mockDoc = angular.element('<html><head></head><body></body></html>'); module(function($provide) { $provide.value('$document', mockDoc); }); }); beforeEach(inject(function(_myService_) { myService = _myService_; })); it('should append my-directive to body element', function() { myService.doTheJob(); // Check mock's body to contain target directive expect(mockDoc.find('body').html()).toContain('<my-directive></my-directive>'); }); });
因此,问题是创建这种模拟的最佳方法是什么?
进行真正的测试document会使我们在每次测试后清理时遇到很多麻烦,而且看起来并不可行。
document
我还尝试过在每次测试之前创建一个新的真实文档实例,但最终都失败了。
创建如下所示的对象并检查whatever变量的工作原理,但看起来非常丑陋
whatever
var whatever = []; var fakeDoc = { find: function(tag) { if (tag == 'body') { return function() { var self = this; this.append = function(content) { whatever.add(content); return self; }; }; } } }
我觉得我在这里错过了一些重要的事情,做错了很严重的事情。
任何帮助深表感谢。
$document在这种情况下,您不需要模拟服务。仅使用其实际实现会更容易:
describe('Sample test', function() { var myService; var $document; beforeEach(function() { module('plunker'); }); beforeEach(inject(function(_myService_, _$document_) { myService = _myService_; $document = _$document_; })); it('should append my-directive to body element', function() { myService.doTheJob(); expect($document.find('body').html()).toContain('<my-directive></my-directive>'); }); });
在这里插一下。
如果您真的需要模拟它,那么我想您将必须像以前那样做:
$documentMock = { ... }
但这可能会破坏依赖$document服务本身的其他情况(例如,使用的指令createElement)。
createElement
更新
如果您需要在每次测试后将文档还原到一致状态,则可以按照以下步骤进行操作:
afterEach(function() { $document.find('body').html(''); // or $document.find('body').empty() // if jQuery is available });
在这里插入(我必须使用另一个容器,否则不会呈现Jasmine结果)。
正如@AlexanderNyrkov在评论中指出的那样,Jasmine和Karma都在body标签内具有自己的内容,并且通过清空文档正文来清除它们似乎不是一个好主意。
body
更新2
我设法对$document服务进行了部分模拟,因此您可以使用实际的页面文档并将所有内容恢复为有效状态:
beforeEach(function() { module('plunker'); $document = angular.element(document); // This is exactly what Angular does $document.find('body').append('<content></content>'); var originalFind = $document.find; $document.find = function(selector) { if (selector === 'body') { return originalFind.call($document, 'body').find('content'); } else { return originalFind.call($document, selector); } } module(function($provide) { $provide.value('$document', $document); }); }); afterEach(function() { $document.find('body').html(''); });
想法是body用新标签替换该标签,您的SUT可以自由操作该标签,并且可以在每个规范的结尾安全地清除测试。