【问题标题】:Testing Involving Database测试涉及数据库
【发布时间】:2017-06-17 14:33:35
【问题描述】:

在说明我的问题之前,我想告诉你我是测试领域的新手,所以这是我的问题:

我使用 express + sequelize(mysql) 开发了一个 rest api,我想为我的 api 编写一些测试。我选择使用 jasmine 库进行测试。

所以知道我想测试createupdate 休息端点,我需要访问一个数据库,但问题是测试用例是并行运行的,并且只有一个数据库,所以如果我想从测试用例的表中删除所有项目,而另一个测试用例在该表中创建了一行,则会出现问题。

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);
            }


        });

    });



});

【问题讨论】:

  • 另一个可能更适合您的测试框架是 pyresttest。您只需定义您期望的请求和响应的样子,然后它就可以检查它。
  • @HSchmale 感谢您的提议,但我想学习如何进行一般测试,所以无论如何我都需要解决这个问题。

标签: node.js unit-testing express testing jasmine


【解决方案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(){});

...所以实际上什么都不做,而不是调用服务器。

这显然需要对您的代码进行一些重写,这可以通过模拟来避免,但会起作用。我的建议是花一些时间学习如何使用模拟框架。从长远来看,它会得到回报。

抱歉,这有点久了。不幸的是,您正在进入一个复杂的单元测试领域,了解您在做什么很重要。我强烈建议您在继续之前阅读有关单元测试的内容,因为对基础知识的良好理解将为您以后省去很多麻烦。罗伯特马丁(又名鲍勃叔叔)在这个主题上的任何内容都会很好,但网络上有很多资源。

希望这会有所帮助。如果您想了解更多信息或说明,请随时询问。

【讨论】:

  • 感谢您的详细解释:),我只想知道是否有一本好的测试教科书。
  • @karim 周围有很多好书。我不能推荐任何具体的,因为我通过阅读 Bob 博士的文章和四处搜索其他文章学到了大部分知识。 youtube 上有很多关于这个主题的视频,所以可能值得一看。
  • @karim 忘了提及,如果您对任何强类型的 OO 语言感到满意,那么首先使用其中一种语言来研究 TDD 是值得的。你会发现这比尝试从 Javascript 开始要容易得多。
【解决方案2】:

Jasmine 支持 beforeEach 的函数,该函数在描述块中的每个规范之前运行。 你可以使用它。

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 处理删除操作。

【讨论】:

    猜你喜欢
    • 2011-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-14
    • 2020-03-01
    相关资源
    最近更新 更多