企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
在前后台分离开发中,我们在进行前台开发时,后台的工作正在进行中,或是还没有进行。这就要求我们在合作开发中,做下以下两点: 1. 100%的模拟后台的数据返回。 2. 当后台开发完毕后,前台与后台能够无缝对接。 本节中,我们再次对M层进行重构,以达到上述目的。 # 重构M层 我们首先,将业务代码实现进行剥离,这样开发起来,架构更清晰。 ``` 'use strict'; /** * @ngdoc service * @name webAppApp.teacher * @description * # teacher * Service in the webAppApp. */ angular.module('webAppApp') .service('teacher', function() { // 获取所有教师 var all = function(callback) { var teachers = [ { name: '张三', username: 'zhangsan', sex: 0, email: 'zhangsan@yunzhiclub.com' }, { name: '李四', username: 'lisi', sex: 1, email: 'lisi@yunzhiclub.com' } ]; callback(teachers); }; // Public API here return { // 获取考场编排信息 all: function(callback) { all(callback); }, }; }); ``` 然后,我们将json数据单独的建立一个资源文件,并模拟请求这个文件。 app/resource/teacher/all.json ``` { "teachers":[ {"username":"zhangsan", "name":"张三", "sex":0,"email":"zhangsan@yunzhiclub.com"}, {"username":"lisi", "name":"李四", "sex":1,"email":"lisi@yunzhiclub.com"}] } ``` > 注意:json文件的格式要求较为严格,sublime有json格式的自动查错功能。在输写时,要特别注意数据格式。否则,进行数据请求时,将返回语法错误的提示。 请求该模拟数据文件: ``` ... // 获取所有教师 var all = function(callback) { // $http.get().then(function1(){}, function2(){}); 链式调用 then()中接收两个参数,类型均为function $http.get('resource/teacher/all.json').then(function success(response) { // 数据成功返回 console.log(response); var teachers = response.data.teachers; callback(teachers); }, function error(response) { console.log('数据请求错误:'); console.log(response); }); }; ... ``` # 测试 此时,我们在刷新链接[http://localhost:9000/#!/teacher/](http://localhost:9000/#!/teacher/), 教师数据成功返回。 todo:截取到有控制台的图 ## 单元测试 我们前面说过,每进行一项开发,我们均需要有单元测试的支持,来保证我们程序开的正确性。当然,这也是分层分工合作的前提,比如团队现在给你的任务是做M层开发。并不涉及到C层与V层,那我们如果在只有M层的前提下,来保证代码的质量呢?答案是唯一的:单元测试。 上面,我们将内部的hardcode变得资源文件后,涉及到了资源请求引起异步的问题。由于异步的存在,这使得我们原来的单元测试失效。 > javascript在两种情况下将异步执行:1.进行资源请求时. 2.执行timeout()进行延时时。 为了排除其它单元测试对我们的影响,我们先去除C层测试中的测试代码: test/spec/controllers/teacher/index.js ``` ... it('测试M层的静态数据', function() { // expect(scope.teachers.length).toBe(2); // expect(scope.teachers[0].username).toBe('zhangsan'); }); ... ``` 然后改写M层的测试代码: test/spec/services/teacher.js ``` ... it('应该取出来所有的教师数据', function() { // $httpBackend.flush(); var teachers; console.log('开始执行异步请求函数'); teacher.all(function(data) { teachers = data; console.log('获取教师数据如下:'); console.log(teachers); }); console.log('结束执行异步请求函数'); }); ... ``` 然后查看控制台: ``` cket AskAaTUxX9RPo52mAAAA with id 64850930 LOG: '开始执行异步请求函数' LOG: '结束执行异步请求函数' PhantomJS 2.1.1 (Mac OS X 0.0.0): Executed 5 of 5 SUCCESS (0.008 secs / 0.041 secs) ``` 是的,正如我们看到的一样,karma单元测试工具,并没有成功的执行带有资源请求的回调函数。 ## ngMock 鉴于此,angularjs给出了ngMock来解决这个问题, 我们在此使用其`$httpBackend`服务。 > ngMock官方文档:[https://docs.angularjs.org/api/ngMock](https://docs.angularjs.org/api/ngMock), $httpBackend[https://docs.angularjs.org/api/ngMock/service/$httpBackend](https://docs.angularjs.org/api/ngMock/service/$httpBackend) test/spec/services/teacher.js ``` 'use strict'; describe('Service: teacher', function() { // load the service's module beforeEach(module('webAppApp')); // instantiate service var teacher, $httpBackend; // 引用$httpBackend beforeEach(inject(function(_teacher_, _$httpBackend_) { teacher = _teacher_; $httpBackend = _$httpBackend_; // 定义请求 URL var url = 'resource/teacher/all.json'; // 定义返回数据。注意此处的json数据的写法与xxx.json文件中的json数据的写的法的异同。 var data = { teachers: [ { username: 'zhangsan', name: '张三', sex: 0, email: 'zhangsan@yunzhiclub.com' }, { username: 'lisi', name: '李四', sex: 1, email: 'lisi@yunzhiclub.com' } ] }; // 进行模似数据请求配置.当请求方法为GET,资源名为resource/teacher/index/all.json, 返回data数据. $httpBackend.when('GET', url).respond(data); })); it('should do something', function() { expect(!!teacher).toBe(true); }); it('应该取出来所有的教师数据', function() { // 调用teacher中的all方法,并在回调函数中执行测试 teacher.all(function(teachers){ expect(teachers.length).toBe(2); }); // 模拟数据请求 $httpBackend.flush(); }); }); ``` 我们在`beforeEach`进行了模拟请求的配置,这保证了每执行一次`it()`,`beforeEach`中的代码都会被执行一次。`$httpBackend.flush();`相当于执行了数据的模拟请求。这为我们执行异步的回调函数创造了条件. > git checkout -f step8.2.3 <hr /> 延伸: 可能你已经发现了,在进行单元测试时,我们实际上并没有真正的请求`app/resource/teacher/index/all.json`这个json文件。那么是不是这个文件的存在就失去意义了呢? 答案是否定的,这个json文件存在很有必要,原因最少有以下几点: 1. 为C层开发的数据对接提供基础. 2. 为后台的数据对接提供示例. 3. 为后期我们可能引用的e2e(端对端)测试提供基础。 > e2e(端对端)测试:一个神奇的可以自动替我们在页面中输入内容,点击按钮,并查看结果的测试方法。 <hr /> 参考资料: google关键字:`angularjs $http test` > Angular-mock之使用$httpBackend服务测试$http: [https://segmentfault.com/a/1190000003716613](https://segmentfault.com/a/1190000003716613) > How to unit test Angular’s $resource and $http: [http://blog.davidjs.com/2013/09/tricky-unit-testing-of-httpbackend/](http://blog.davidjs.com/2013/09/tricky-unit-testing-of-httpbackend/)