我使用express + sequelize(mysql)开发了一个rest api,我想为我的api编写一些测试。我选择使用茉莉花库进行测试。
所以我知道我想测试create
和update
休息端点,我需要访问数据库,但问题是测试用例并行运行,并且只有一个数据库,所以如果我想从测试用例中的表中删除所有项目,而另一个测试用例在该表中创建了一行,则会出现问题。
const request = require('superagent');
const models = require('../../src/models');
const Station = models.Station;
describe("station testing", function () {
before(() => {
// delete and recreate all database table
// before running any test
});
describe("crud station", function () {
it('should create model', () => {
Station.create({
'name': 'test',
lat: 12,
long: 123,
}).then( model => {
expect(model).toBeTruthy();
});
});
it('should delete evrything', () => {
Station.deleteAll().then( () => {
// problem here if after the first model is created and before create model except is executed
expect(Station.Count()).toEqual(0);
}
});
});
});
答案 0 :(得分:1)
Jasmine支持beforeEach的函数,该函数在describe块中的每个规范之前运行。 你可以使用它。
describe("A spec using beforeEach and afterEach", function() {
var foo = 0;
beforeEach(function() { foo += 1; });
afterEach(function() { foo = 0; });
it("is just a function, so it can contain any code", function() {
expect(foo).toEqual(1);
});
it("can have more than one expectation", function() {
expect(foo).toEqual(1)
expect(true).toEqual(true);
});
});
所以你可以让beforeEach处理删除操作。
答案 1 :(得分:1)
你的问题是你不是在这里写单元测试。
您需要了解最重要的单元测试规则 - 一次只测试一个单元。可以将单元视为代码的一个区域。在传统的桌面项目(Java,C#等)中,一个单元将是一个类。在Javascript的情况下,单元更难定义,但肯定仅包含Javacript。如果您在测试中包含任何服务器代码(例如,数据库),那么您不是单元测试,而是进行集成测试(这也非常重要,但更难)。
您的Javascript将具有依赖项(即它调用的其他代码,例如通过Ajax调用),在您的情况下将包含被调用的服务器代码。为了进行单元测试,您需要确保仅测试Javascript,这意味着在运行测试时,您根本不希望调用服务器代码。这样,您可以隔离该代码单元中的任何错误,并且可以确信发现的任何问题确实存在于该单元中。如果您包含其他单位,则可能是其他单位遇到问题。
在强类型语言(如Java,C#等)中,有一些框架允许您为每个依赖项设置模拟。虽然我自己没有尝试过(本周的工作),但有mocking frameworks for Javascript,您可能需要使用其中一个来进行真正的单元测试。你模拟了服务器代码,所以当你运行测试时,它实际上并没有真正命中数据库。除了解决您的问题之外,它还避免了您在当前方法中可能遇到的其他问题。
如果您不想使用模拟框架,另一种方法是更改您的Javascript,以便您正在测试的功能需要一个额外的参数,这是一个执行实际服务器调用的函数。所以,而不是......
deleteCustomer(42);
deleteCustomer(id) {
validate(id);
$.ajax(...);
}
...你的代码看起来像这样......
deleteCustomer(42, callServer);
deleteCustomer(id, serverCall) {
validate(id);
serverCall(id);
}
...其中serverCall()
包含Ajax调用。
然后,对于单元测试,你会测试这样的东西......
deleteCustomer(42, function(){});
...所以不是调用服务器,实际上什么也没做。
这显然需要对代码进行一些重写,这可以通过模拟来避免,但可以正常工作。我的建议是花一些时间学习如何使用模拟框架。从长远来看,它会得到回报。
对不起,这已经有点长了。不幸的是,您正在进入一个复杂的单元测试领域,了解您正在做的事情非常重要。我强烈建议您在进一步了解之前阅读有关单元测试的内容,因为对基础知识的充分理解将为您节省很多麻烦。罗伯特·马丁(又名鲍勃叔叔)关于这个问题的任何内容都会很好,但网上有很多资源。
希望这会有所帮助。如果您想了解更多信息或澄清,请随时提出。