编写 angular2 测试并更改模拟 return 值 - 使其变干?
Write angular2 tests and changing the mock return values - make it DRY?
我正在为服务编写一些测试,并且正在更改模拟函数的响应以测试各种情况。目前,每次我想更改模拟的响应时,我都需要重置 TestBed 并再次配置测试模块,将我的新模拟作为依赖项注入。
我觉得一定有一种 DRYer 的方式来编写这个规范,但我想不出来。有人有什么想法吗?
(我知道我可以将此服务的测试编写为标准 ES6 class,但我的组件和服务使用来自 angular 的 Http 响应模拟内容时遇到了相同的情况.)
这是我的规范文件:
import { TestBed, inject } from '@angular/core/testing';
import { Observable } from 'rxjs/Observable';
import { UserService, RestService } from '../index';
import { User } from '../../../models/index';
let getUserSpy = jasmine.createSpy('getUser');
let upsertUserSpy = jasmine.createSpy('upsertUser');
// NOTE that initally, the MockRestService throws errors for all responses
class MockRestService {
getUser = getUserSpy.and.returnValue(Observable.throw('no thanks'));
upsertUser = upsertUserSpy.and.returnValue(Observable.throw('no thanks'));
}
describe('User service - ', () => {
let service;
/**
* First TestBed configuration
*/
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
UserService,
{
provide: RestService,
useClass: MockRestService,
}
]
});
});
beforeEach(inject([UserService], (user: UserService) => {
service = user;
}));
/* ... tests ... */
describe('getUser/ upsertUser succeeds with INVALID user - ', () => {
/**
* Altering mock
*/
class MockRestService {
getUser = getUserSpy.and.returnValue(Observable.of({json: () => {
return {name: 'dave'};
}}));
upsertUser = upsertUserSpy.and.returnValue(Observable.of({json: () => {}}));
}
/**
* Reset and reconfigure TestBed. Lots of repetition!
*/
beforeEach(() => {
TestBed.resetTestingModule();
});
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
UserService,
{
provide: RestService,
useClass: MockRestService,
}
]
});
});
beforeEach(inject([UserService], (user: UserService) => {
service = user;
}));
/* ... tests ... */
});
describe('getUser/upsertUser succeeds with valid user', () => {
const validResponse = {
json: () => {
return {
firstName: 'dave',
lastName: 'jones',
email: 'dave@gmail.com'
};
}
};
/**
* Altering mock
*/
class MockRestService {
getUser = getUserSpy.and.returnValue(Observable.of(validResponse));
upsertUser = upsertUserSpy.and.returnValue(Observable.of(validResponse));
}
/**
* Reset and reconfigure testbed. Lots of repetition!
*/
beforeEach(() => {
TestBed.resetTestingModule();
});
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
UserService,
{
provide: RestService,
useClass: MockRestService,
}
]
});
});
beforeEach(inject([UserService], (user: UserService) => {
service = user;
}));
/* ... tests ... */
});
});
可能是
的一些变体
function setupUserTestbed() {
beforeEach(() => {
TestBed.configureTestingModule({...});
});
afterEach(() => {
TestBed.resetTestingModule();
});
}
...
setupUserTestbed();
...
setupUserTestbed();
但是 describe
块的目的(除了在测试报告中对规格进行分组之外)是以最有效的方式排列 before*
和 after*
块。
如果顶级 describe
块有 beforeEach
块,您可以确定它会影响嵌套 describe
块中的规范。如果 describe
块是兄弟块,则应将常见行为移至顶层 describe
。如果兄弟 describe
块没有顶级 describe
,则应该创建它。
在发布的代码中,顶层 describe('User service - ', () => { ... })
已经有 beforeEach
个块 TestBed.configureTestingModule
、TestBed.resetTestingModule
(应该在 afterEach
中执行)和 inject
。无需在嵌套的 describe
块中复制它们。
MockRestService
class 的配方与任何在规范之间交替的模拟相同。它应该是一个 let
/var
变量:
describe(...
let MockRestService = class MockRestService { ... };
beforeEach(() => { Testbed... });
describe(...
MockRestService = class MockRestService { ... };
beforeEach(inject(...));
这种模式可以有很多变化。 class 本身可能是常量,但 getUser
和 upsertUser
属性可能会交替:
let getUserSpy;
let upsertUserSpy;
class MockRestService {
getUser = getUserSpy;
...
}
describe(...
beforeEach(() => { Testbed... });
beforeEach(() => {
getUserSpy = jasmine.createSpy().and.returnValue(...);
...
});
describe(...
beforeEach(() => {
getUserSpy = jasmine.createSpy().and.returnValue(...);
...
});
beforeEach(inject(...));
这也解决了一个重要的问题,因为间谍在每个规范中都应该是新鲜的,即在 beforeEach
中定义。 getUserSpy
和 upsertUserSpy
可以在 Testbed
配置之后但在 inject
之前重新分配(这是 MockRestService
class 可能实例化的地方)。 =41=]
我正在为服务编写一些测试,并且正在更改模拟函数的响应以测试各种情况。目前,每次我想更改模拟的响应时,我都需要重置 TestBed 并再次配置测试模块,将我的新模拟作为依赖项注入。
我觉得一定有一种 DRYer 的方式来编写这个规范,但我想不出来。有人有什么想法吗?
(我知道我可以将此服务的测试编写为标准 ES6 class,但我的组件和服务使用来自 angular 的 Http 响应模拟内容时遇到了相同的情况.)
这是我的规范文件:
import { TestBed, inject } from '@angular/core/testing';
import { Observable } from 'rxjs/Observable';
import { UserService, RestService } from '../index';
import { User } from '../../../models/index';
let getUserSpy = jasmine.createSpy('getUser');
let upsertUserSpy = jasmine.createSpy('upsertUser');
// NOTE that initally, the MockRestService throws errors for all responses
class MockRestService {
getUser = getUserSpy.and.returnValue(Observable.throw('no thanks'));
upsertUser = upsertUserSpy.and.returnValue(Observable.throw('no thanks'));
}
describe('User service - ', () => {
let service;
/**
* First TestBed configuration
*/
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
UserService,
{
provide: RestService,
useClass: MockRestService,
}
]
});
});
beforeEach(inject([UserService], (user: UserService) => {
service = user;
}));
/* ... tests ... */
describe('getUser/ upsertUser succeeds with INVALID user - ', () => {
/**
* Altering mock
*/
class MockRestService {
getUser = getUserSpy.and.returnValue(Observable.of({json: () => {
return {name: 'dave'};
}}));
upsertUser = upsertUserSpy.and.returnValue(Observable.of({json: () => {}}));
}
/**
* Reset and reconfigure TestBed. Lots of repetition!
*/
beforeEach(() => {
TestBed.resetTestingModule();
});
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
UserService,
{
provide: RestService,
useClass: MockRestService,
}
]
});
});
beforeEach(inject([UserService], (user: UserService) => {
service = user;
}));
/* ... tests ... */
});
describe('getUser/upsertUser succeeds with valid user', () => {
const validResponse = {
json: () => {
return {
firstName: 'dave',
lastName: 'jones',
email: 'dave@gmail.com'
};
}
};
/**
* Altering mock
*/
class MockRestService {
getUser = getUserSpy.and.returnValue(Observable.of(validResponse));
upsertUser = upsertUserSpy.and.returnValue(Observable.of(validResponse));
}
/**
* Reset and reconfigure testbed. Lots of repetition!
*/
beforeEach(() => {
TestBed.resetTestingModule();
});
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
UserService,
{
provide: RestService,
useClass: MockRestService,
}
]
});
});
beforeEach(inject([UserService], (user: UserService) => {
service = user;
}));
/* ... tests ... */
});
});
可能是
的一些变体function setupUserTestbed() {
beforeEach(() => {
TestBed.configureTestingModule({...});
});
afterEach(() => {
TestBed.resetTestingModule();
});
}
...
setupUserTestbed();
...
setupUserTestbed();
但是 describe
块的目的(除了在测试报告中对规格进行分组之外)是以最有效的方式排列 before*
和 after*
块。
如果顶级 describe
块有 beforeEach
块,您可以确定它会影响嵌套 describe
块中的规范。如果 describe
块是兄弟块,则应将常见行为移至顶层 describe
。如果兄弟 describe
块没有顶级 describe
,则应该创建它。
在发布的代码中,顶层 describe('User service - ', () => { ... })
已经有 beforeEach
个块 TestBed.configureTestingModule
、TestBed.resetTestingModule
(应该在 afterEach
中执行)和 inject
。无需在嵌套的 describe
块中复制它们。
MockRestService
class 的配方与任何在规范之间交替的模拟相同。它应该是一个 let
/var
变量:
describe(...
let MockRestService = class MockRestService { ... };
beforeEach(() => { Testbed... });
describe(...
MockRestService = class MockRestService { ... };
beforeEach(inject(...));
这种模式可以有很多变化。 class 本身可能是常量,但 getUser
和 upsertUser
属性可能会交替:
let getUserSpy;
let upsertUserSpy;
class MockRestService {
getUser = getUserSpy;
...
}
describe(...
beforeEach(() => { Testbed... });
beforeEach(() => {
getUserSpy = jasmine.createSpy().and.returnValue(...);
...
});
describe(...
beforeEach(() => {
getUserSpy = jasmine.createSpy().and.returnValue(...);
...
});
beforeEach(inject(...));
这也解决了一个重要的问题,因为间谍在每个规范中都应该是新鲜的,即在 beforeEach
中定义。 getUserSpy
和 upsertUserSpy
可以在 Testbed
配置之后但在 inject
之前重新分配(这是 MockRestService
class 可能实例化的地方)。 =41=]