【问题标题】:Jasmine async tests inside loop are not working as expected循环内的 Jasmine 异步测试未按预期工作
【发布时间】:2015-05-18 17:05:05
【问题描述】:

我为使用 Jasmine 构建的 node.js 驱动 API 编写了一些单元测试。

测试工作正常,但现在我想用不同的输入运行一组异步测试,但我无法让它工作。

我的测试在 URL 中使用“偏移”和“限制”参数对 API 运行一些请求,并且 API 在响应中插入分页链接(第一个、上一个、下一个和最后一个)。

这是我的茉莉花测试:

describe('API with "limit" and "offset" parameters', function() {

    var offset = 0;
    var limit = 4;
    var url = baseUrl + '?limit=' + limit + '&offset=' + offset;

    beforeEach(function(done) {
        request.get(url, function(err, res, resBody) {
            response = res;
            body = JSON.parse(resBody);
            count = body.count;
            done();
        });
    });

    it('should respond with status code 200', function(done) {
        expect(response.statusCode).toEqual(200);
        done();
    });

    it('should have a response with [limit] results if count - offset >= limit, otherwise count - offset', function(done) {
        if(count - offset >= limit) expect(body.rows.length).toEqual(limit);
        else expect(body.rows.length).toEqual(count - offset);
        done();
    });

    it('should have navigation links', function(done) {
        expect(body.first).toBeDefined();
        expect(body.prev).toBeDefined();
        expect(body.next).toBeDefined();
        expect(body.last).toBeDefined();
        done();
    });

    it('should have "first" navigation link equal to url offset=0 and limit=limit', function(done) {
        expect(body.first).toEqual(baseUrl + '?limit=' + limit + '&offset=0');
        done();
    });

    it('should have "prev" navigation link equal to null if offset=0, otherwise offset = offset - limit', function(done) {
        if(offset ===0) expect(body.prev).toBeNull();
        else expect(body.prev).toEqual(baseUrl + '?limit=' + limit + '&offset=' + (offset - limit));
        done();
    });

    it('should have "next" navigation link equal to offset + limit, or null if offset+limit > count', function(done) {
        if(offset + limit <= count) expect(body.next).toEqual(baseUrl + '?limit=' + limit + '&offset=' + (offset + limit));
        else expect(body.next).toBeNull();
        done();
    });

    it('should have "last" navigation link equal to floor(count/limit)*limit', function(done) {
        expect(body.last).toEqual(baseUrl + '?limit=' + limit + '&offset=' + Math.floor(count/limit) * limit);
        done();
    });
});

此测试运行良好,但现在我想重复运行此测试,在每次运行中将“偏移”递增“限制”,直到到达最后一页(即偏移 + 限制 >= 计数),但我不能让这个工作。

到目前为止我已经尝试过什么

我的第一个想法是将测试放在一个循环中,包含在一个 IIFE 中,但这不起作用,因为 for 循环中的“count”是未定义的(我猜它只能在“it”中使用):

for(var i=offset; i<count; i+=limit) {  // "count" is undefined here

        (function(offset, count, limit) {

            it('should have "first" navigation link equal to url offset=0 and limit=limit', function(done) {
                expect(body.first).toEqual(baseUrl + '?limit=' + limit + '&offset=0');
                done();
            });

            it('should have "prev" navigation link equal to null if offset=0, otherwise offset = offset - limit', function(done) {
                if(offset ===0) expect(body.prev).toBeNull();
                else expect(body.prev).toEqual(baseUrl + '?limit=' + limit + '&offset=' + (offset - limit));
                done();
            });

            it('should have "next" navigation link equal to offset + limit, or null if offset+limit > count', function(done) {
                if(offset + limit <= count) expect(body.next).toEqual(baseUrl + '?limit=' + limit + '&offset=' + (offset + limit));
                else expect(body.next).toBeNull();
                done();
            });

            it('should have "last" navigation link equal to floor(count/limit)*limit', function(done) {
                expect(body.last).toEqual(baseUrl + '?limit=' + limit + '&offset=' + Math.floor(count/limit) * limit);
                done();
            });
        })(offset, count, limit);
    }

我的第二个想法是在“afterAll”中进行递增,再次将测试包装在 IIFE 中。 似乎 afterAll 确实再次运行 runTests() (我看到出现了 console.log)但测试本身没有再次运行:

(function runTests(offset, count, limit) {
        console.log('running tests');
        beforeEach(function(done) {
            request.get(url, function(err, res, resBody) {
                response = res;
                body = JSON.parse(resBody);
                count = body.count;
                done();
            });
        });

        it('should have "first" navigation link equal to url offset=0 and limit=limit', function(done) {
            expect(body.first).toEqual(baseUrl + '?limit=' + limit + '&offset=0');
            done();
        });

        it('should have "prev" navigation link equal to null if offset=0, otherwise offset = offset - limit', function(done) {
            if(offset ===0) expect(body.prev).toBeNull();
            else expect(body.prev).toEqual(baseUrl + '?limit=' + limit + '&offset=' + (offset - limit));
            done();
        });

        it('should have "next" navigation link equal to offset + limit, or null if offset+limit > count', function(done) {
            console.log('next', offset, limit, count);
            if(offset + limit <= count) expect(body.next).toEqual(baseUrl + '?limit=' + limit + '&offset=' + (offset + limit));
            else expect(body.next).toBeNull();
            done();
        });

        it('should have "last" navigation link equal to floor(count/limit)*limit', function(done) {
            expect(body.last).toEqual(baseUrl + '?limit=' + limit + '&offset=' + Math.floor(count/limit) * limit);
            done();
        });

        afterAll(function() {
            offset += limit;

            if(offset < count) runTests(offset, count, limit);
        });
    })(offset, count, limit);

我在这里做错了什么?还有其他方法可以让这个工作吗?

更新:这是我基于 Zlatko 回答的完整工作代码:

describe('API with "limit" and "offset" parameters', function() {

    var offset = 0;
    var limit = 4;
    var url = baseUrl + '?limit=' + limit + '&offset=' + offset;

    function testNavLinks(limit, offset, url) {

        describe('Check navigation links with offset = ' + offset, function() {

            var response;
            var count;
            var body;

            beforeEach(function(done) {
                request.get(url, function(err, res, resBody) {
                    response = res;
                    body = JSON.parse(resBody);
                    count = body.count;
                    done();
                });
            });

            it('should respond with status code 200', function(done) {
                expect(response.statusCode).toEqual(200);
                done();
            });

            it('should have a response with [limit] results if count - offset >= limit, otherwise count - offset', function(done) {
                if(count - offset >= limit) expect(body.rows.length).toEqual(limit);
                else expect(body.rows.length).toEqual(count - offset);
                done();
            });

            it('should have navigation links', function(done) {
                expect(body.first).toBeDefined();
                expect(body.prev).toBeDefined();
                expect(body.next).toBeDefined();
                expect(body.last).toBeDefined();
                done();
            });

            it('should have "first" navigation link equal to url offset=0 and limit=limit', function(done) {
                expect(body.first).toEqual(baseUrl + '?limit=' + limit + '&offset=0');
                done();
            });

            it('should have "prev" navigation link equal to null if offset=0, otherwise offset = offset - limit', function(done) {
                if(offset === 0) expect(body.prev).toBeNull();
                else expect(body.prev).toEqual(baseUrl + '?limit=' + limit + '&offset=' + (offset - limit));
                done();
            });

            it('should have "next" navigation link equal to offset + limit, or null if offset+limit > count', function(done) {
                if(offset + limit <= count) expect(body.next).toEqual(baseUrl + '?limit=' + limit + '&offset=' + (offset + limit));
                else expect(body.next).toBeNull();
                done();
            });

            it('should have "last" navigation link equal to floor(count/limit)*limit', function(done) {
                expect(body.last).toEqual(baseUrl + '?limit=' + limit + '&offset=' + Math.floor(count/limit) * limit);
                done();
            });
        });
    }
    // 13 is the actual number of results
    // I did not manage to get the actual number from the response, see my comment below
    for(var i=0; i<13; i+=limit) {
        url = baseUrl + '?limit=' + limit + '&offset=' + i;
        testNavLinks(limit, i, url);
    }
});

【问题讨论】:

    标签: javascript node.js unit-testing jasmine


    【解决方案1】:

    因此,您尝试多次重复测试,但根本不需要处理 IIFE。只需让你的测试成为一个函数,然后从循环中调用它:

    describe('Loop an async set of tests.', function() {
    
      var baseUrl = process.env.API_URL; // or whatever
      function loopMyApi(offset, limit) {
    
        // add a new suite
        describe('Calling at offset: ' + offset , function() {
    
          var response;
          var myUrl = baseUrl + '?limit=' + limit + '&offset=' + offset;
          beforeEach(function(done) {
    
            request(myUrl, function(err, res) {
    
              if (err) {throw err;}
              response = res;
              done();
            });
          });
    
          it('should have length', function() {
    
            // btw since response is already here, this test is now sync
            // no need for `done`.
            response.body.length.should.equal(limit);
          });
          it('should be ok', function() {
            response.statusCode.should.be.lessThan(399);
          });
        });
      }
      var limit = 10;
      // you can start like this, or just make a regular for
      // loop as you have in your examples.
      [0, 10, 20, 30].forEach(function(offset) {
    
        // if you want to modify limit for some reason, do it here.
        loopMyApi(offset, limit);
      });
    });
    

    根据需要进行调整以适应您的场景。

    【讨论】:

    • 谢谢,我现在可以正常工作了。唯一的缺点是我必须在 for 循环中硬编码结果的数量(“count”变量)。我的想法是在父“描述”中获取结果的数量,但这不起作用,因为 for 循环显然是在任何规范开始之前运行的(我看到循环内的 console.log 作为第一个输出)
    • 不是 100% 确定我理解您的要求,但如果我理解了,那么您也可以在外部 describe 中执行 beforeEach() 并从那里运行 for 循环?唔。我只是想知道它是否会被处理,因为之前没有 each 可以运行 beforeEach :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-29
    • 2019-04-19
    • 1970-01-01
    • 2018-10-19
    • 1970-01-01
    相关资源
    最近更新 更多