简体   繁体   English

Mocha - 将变量从 `it` 传递给 `beforeEach` 和 `afterEach`

[英]Mocha - pass variable to `beforeEach` and `afterEach` from `it`

This question could solve a lot of general solutions, so I'll try to phrase it in such a way.这个问题可以解决很多通用的解决方案,所以我会尝试用这样的方式来表达它。 I have a situation where I need the same beforeEach and afterEach block of code run but need to alter just one variable (or a couple) each time.我有一种情况,我需要相同的beforeEachafterEach代码块运行,但每次只需要更改一个(或几个)变量。

My specific scenario: I need to insert/delete from a database each time.我的具体场景:我每次都需要从数据库中插入/删除。 Code:代码:

First setting up temporary table for tests:首先为测试设置临时表:

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

Then hooks before/after each test [EDIT with @luboskrnac suggestions] :然后在每次测试之前/之后挂钩[使用@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();
    });
});

Then (temporary) table is cleaned up when session closes.然后(临时)表在会话关闭时被清理。 Is there anyway to pass values as a variable to these hooks for each it test?无论如何,是否将values作为变量传递给每个it测试的钩子?

It is not possible for a it call to constrain what data the beforeEach hook that Mocha will run before the it call will see. it调用不可能限制在it调用之前 Mocha 将运行的beforeEach钩子将看到哪些数据。 The it call can affect what runs after it but not what runs before it. it调用可以影响之后运行的内容,但不会影响之前运行的内容。

What I would do is just move the initialization code to a function that can be called from the tests, and call it in each test.我要做的只是将初始化代码移动到一个可以从测试中调用的函数中,并在每个测试中调用它。 Something like this:像这样的东西:

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

You'll notice I have some additional error checking that was not in your code.你会注意到我有一些额外的错误检查,这些错误检查不在你的代码中。 This is necessary to ensure that errors are reported by Mocha with a maximum of details.这是必要的,以确保 Mocha 报告的错误具有最多的详细信息。 I strongly suggest using a library that returns promises, as it would simplify the code a lot.我强烈建议使用一个返回 promise 的库,因为它会大大简化代码。

The Difference Between Hooks and Having a Shared Function Hooks 和共享函数的区别

Mocha treats test failures and hook ( before , beforeEach , etc.) failures differently. Mocha 以不同的方式对待测试失败和钩子( beforebeforeEach等)失败。 If a test fails, Mocha will continue executing other tests.如果测试失败,Mocha 将继续执行其他测试。 If a hook fails, Mocha considers this to be a failure of the test suite and will skip executing anything that depends on the hook.如果钩子失败,Mocha 认为这是测试套件的失败并且会跳过执行任何依赖于钩子的东西。 Here's a trivial example:这是一个简单的例子:

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", () => {});
});

I get this output when I run Mocha on the above:当我在上面运行 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)

You can see in the first describe block, only the first two tests were run.您可以在第一个describe块中看到,只运行了前两个测试。 As soon as beforeEach fails, Mocha skips the rest of the tests in the describe block, but the 2nd one can be run because it does not depend on the failed hook.只要beforeEach失败,Mocha 就会跳过describe块中的其余测试,但可以运行第二个测试,因为它不依赖于失败的钩子。

So when you use a shared function rather than a hook to initialize data for a test, you are essentially causing Mocha to treat initialization failures as test failures rather than suite failures.因此,当您使用共享函数而不是钩子来初始化测试数据时,实际上是在导致 Mocha 将初始化失败视为测试失败而不是套件失败。 It is debatable where the line falls between tests failures and suite failures and really depends on the details of the project.测试失败和套件失败之间的界限是有争议的,这实际上取决于项目的细节。

If you want to share some state between beforeEach and afterEach just define it in describe scope:如果你想在beforeEachafterEach之间共享一些状态,只需在describe范围内定义它:

describe('...', 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();
        });
    });
});

Pass data between beforeEach, afterEach and it in mocha tests.在 mocha 测试中在 beforeEach、afterEach 和 it 之间传递数据。

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

}); });

It actually is possible to do what you are asking, perhaps it was not in earlier versions of Mocha though.实际上可以按照您的要求执行操作,但可能在早期版本的 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];
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM