摩卡 - 从`it`传递变量到`beforeEach`和`afterEach`

时间:2016-12-05 13:30:29

标签: javascript mocha

这个问题可以解决很多一般的解决方案,所以我会尝试用这种方式来表达它。我有一种情况,我需要运行相同的beforeEachafterEach代码块,但每次只需要改变一个变量(或一对)。

我的具体场景:我每次都需要从数据库中插入/删除。代码:

首先为测试设置临时表:

before(function(done) {
    db.query('CREATE TEMPORARY TABLE tmp AS SELECT * FROM example_table', null, function(error) {
        return done();
    });
});

然后在每次测试之前/之后挂钩 [编辑@luboskrnac建议]

var vals = []

beforeEach(init_vals, function(done) {
    mysql.query('INSERT INTO tmp (a, b) VALUES (?, ?)', init_vals, function(error, rows) {
        return done();
    });
});

// pass values [1, 2] to `beforeEach`
it('check value is in database', function(done) {
    mysql.query('SELECT * FROM tmp WHERE a = ? AND b = ?', function(error, rows) {
        vals = [1, 2];
        expect(rows[0].a === vals.a);
        expect(rows[0].b === vals.b);
        return done(); // pass values
    })
})

afterEach(function(done) {
    mysql.query('DELETE FROM tmp WHERE a = ? AND b = ?', vals, function(error, rows) {
        return done();
    });
});

当会话关闭时,(临时)表被清除。无论如何都要将values作为变量传递给每个it测试的这些钩子?

4 个答案:

答案 0 :(得分:4)

it调用无法限制在beforeEach调用看到之前Mocha将运行的it挂钩数据。 it调用会影响之后运行的内容,但不影响之前运行的内容。

我要做的只是将初始化代码移动到可以从测试中调用的函数,并在每次测试中调用它。像这样:

describe(function () {
    // Record values we may need to clean after the test.
    var to_clean;

    function init(vals, cb) {
        mysql.query('INSERT INTO tmp (a, b) VALUES (?, ?)', vals,
                    function(error, rows) {
                        // Record that we need to clean some values.
                        to_clean = vals;
                        cb(error);
                    });
    }

    it('check value is in database', function(done) {
        var vals = [1, 2];
        init(vals, function (error) {
            if (error) {
                done(error);
                return;
            }

            mysql.query('SELECT * FROM tmp WHERE a = ? AND b = ?',
                        function(error, rows) {
                            if (error) {
                                done(error);
                                return;
                            }

                            // You need to catch these if you want a
                            // precise error report from
                            // Mocha. Otherwise, you get a vague
                            // timeout error.
                            try {
                                expect(rows[0].a === vals.a);
                                expect(rows[0].b === vals.b);
                            }
                            catch(e) {
                                done(e);
                                return;
                            }

                            done();
                        });
        });
    });

    afterEach(function(done) {
        if (to_clean) {
            mysql.query('DELETE FROM tmp WHERE a = ? AND b = ?', to_clean,
                        function(error, rows) {
                            // Reset so that we don't try to clean
                            // obsolete data. Yes, we clear this even
                            // if there was an error.
                            to_clean = undefined;
                            done(error);
                        });
        }
        else {
            // Nothing to clean, we're done.
            done();
        }
    });
});

您会注意到我的代码中没有其他错误检查。这对于确保Mocha报告错误以及最多细节是必要的。我强烈建议使用一个返回promises的库,因为它会简化代码。

挂钩与共享功能之间的区别

Mocha以不同方式处理测试失败和挂钩(beforebeforeEach等)失败。如果测试失败,Mocha将继续执行其他测试。如果一个钩子失败,Mocha认为这是一个失败的测试套件,并将跳过执行任何依赖于钩子的东西。这是一个微不足道的例子:

describe("top", () => {
    let fail = true;
    beforeEach(() => {
        fail = !fail;
        if (fail) {
            throw new Error("fail");
        }
    });

    it("one", () => {});
    it("two", () => {});
    it("three", () => {});
});

describe("top 2", () => {
    it("one", () => {});
    it("two", () => {});
    it("three", () => {});
});

当我在上面运行Mocha时,我得到了这个输出:

  top
    ✓ one
    1) "before each" hook for "two"

  top 2
    ✓ one
    ✓ two
    ✓ three


  4 passing (10ms)
  1 failing

  1) top "before each" hook for "two":
     Error: fail
      at Context.beforeEach (test2.js:6:19)

您可以在第一个describe块中看到,只运行了前两个测试。一旦beforeEach失败,Mocha将跳过describe块中的其余测试,但第二个可以运行,因为它不依赖于失败的钩子。

因此,当您使用共享函数而不是钩子来初始化测试数据时,您实际上会导致Mocha将初始化失败视为测试失败而不是套件失败。这条线在测试失败和套件故障之间落在哪里并且实际上取决于项目的细节是值得商榷的。

答案 1 :(得分:2)

如果您想在beforeEachafterEach之间分享某个州,只需在describe范围内定义:

descibe('...', function () {
    var values = [];
    beforeEach(function(done) {
        mysql.query('INSERT INTO tmp (a, b) VALUES (?, ?)', values, function(error, rows) {
            return done();
        });
    });

    afterEach(function(done) {
        mysql.query('DELETE FROM tmp WHERE a = ? AND b = ?', values, function(error, rows) {
            return done();
        });
    });
});

答案 2 :(得分:0)

在mocha测试中,在beforeEach,afterEach和它之间传递数据。

describe('User Authentication', () => {

before(async () => {
    let oObj = await admin.newAdmin();
    this.username = oObj.login; 
    this.password = oObj.password;
});

it('If the credentials exists in the system it should return the token generated against it.', (done) => {
    chai.request(server)
    .post("/application/login")
    .set("Content-Type", "application/x-www-form-urlencoded")
    .send({username: this.username,password:this.password})
    .end((err, res) => {
        this.token = res.body;
        res.should.have.status(200);
        res.body.should.be.a("string");
        done();
    });
});


it('Get All Books.', (done) => {
    chai.request(server)
    .get("/books/")
    .set("Content-Type", "application/json")
    .set("access_token", this.token)
    .end((err, res) => {
        console.log(res.body);
        res.should.have.status(200);
        res.should.be.an("object");
        res.should.have.property('body').should.be.an('object')
        // res.body.should.be.an('object')
        res.body.should.have.property('results')
        res.body.results.should.be.an('array').to.not.equal(0)
        // res.body.results.should.to.not.equal(0)
        res.body.should.have.property('total').not.equal(0)
        // res.body.total.should.not.equal(0)

        done();
    });
});

});

答案 3 :(得分:0)

实际上可以按照您的要求做,也许不是在早期版本的Mocha中。

describe('My suite', function() {
    beforeEach('Test setup', function() {
        const vals = this.currentTest.vals;
        // insert vals
    });

    afterEach('Test teardown', function() {
        const vals = this.currentTest.vals;
        // delete vals
    });

    const test = it('My test', function() {
        const vals = this.test.vals;
        // verify vals
    });
    test.vals = [1, 2];
});