测试中不寻常的行为:node.js / Mocha

时间:2016-10-28 12:55:17

标签: node.js express testing tdd mocha

我最近跳进了nodeJS并开始使用Express& amp ;;来构建中间件应用程序。 Wagnor

下面的

是我的package.JSON

find

我陷入了一种非常奇怪的境地,并搜索了类似的事件报告,但无法获得任何相关信息。我确信我犯的是一个愚蠢的错误,需要帮助来识别它。

这是一个场景,我有一个带有6个端点的基本中间件设置,我正在使用mocha进行测试。

我有一个带有6个测试的test.js文件,问题是当我运行它时它会传递一次并再次失败然后再次传递而不需要任何干预env或代码或测试。这使我非常担心天气我的应用程序在生产中的行为类似,或者是与测试相关的问题或已知的摩卡问题(无法找到)。

以下是我的测试文件

{
"devDependencies": {
  "gulp": "3.8.11",
  "gulp-mocha": "2.0.1",
  "mocha": "2.2.4",
  "superagent": "1.2.0",
  "wagner-core": "0.1.0"
 },
  "dependencies": {
    "underscore": "1.5.2",
  "mongodb": "2.2.10",
  "express": "",
  "http-status": "0.1.8",
  "mongoose":""
 },
 "scripts": {
 "test": "mocha test.js"
 }
 }

当我运行这些测试时,会发生以下情况: a)6次测试通过 b)一些测试失败 c)有一个空白的回复

var URL_ROOT = 'http://localhost:3131';
var express = require('express');
var wagner = require('wagner-core');
var assert = require('assert');
var superagent = require('superagent');
var mongoose = require('mongoose');
//mongoose.set('debug', true);

var PRODUCT_ID = '0000000000000000000001';

describe('Store API', function(){
    var server; 
    var Product;
    var Catagory;
    var User;


    before(function() {
        var app = express();

        // Bootstrap sertver
        models = require('./models')(wagner);
        require('./dependencies')(wagner);
        app.use(require('./api')(wagner));
        wagner.invoke(require('./auth'), {app: app});
        server = app.listen(3131);

        //Make Catagory and Product model available in test
        Catagory = models.Catagory;
        Product = models.Product;
        User = models.User;


        app.use( function(req, res, next) {
          User.findOne({}, function(error, user) {
               console.log('Time:', Date.now());
               assert.ifError(error);
               req.user = user;
               next();
           });  //user.findone
       }); //app.use
    }); //before

    after(function(){
        //Shut the server
        server.close();
    }); //after

    beforeEach(function(done) {
        //Make sure Catagories are empty before each test
        Catagory.remove({}, function(error) {
            assert.ifError(error);
            Product.remove({}, function(error) {
                assert.ifError(error);
                User.remove({}, function(error) {
                    assert.ifError(error);
                    //Create Products, Catagories and Users
                    var catagories = [
                        { _id: 'Electronics'},
                        { _id: 'Phones', parent: 'Electronics'},
                        { _id: 'Laptop', parent: 'Electronics'},
                        { _id: 'Meat'}
                    ];

                    // create product data
                    var products = [
                        {
                            _id: '00000000000001',
                            name: 'LG G4',
                            catagory: { _id: 'Phones', ancestors: ['Electronics', 'Phones']},
                            price: {
                                amount: 300,
                                currency: 'USD'
                            }
                        },
                        {
                            _id: '00000000000002',
                            name: 'Asus Zenbook Prime',
                            catagory: { _id: 'Laptop', ancestors: ['Electronics', 'Laptop']},
                            price: {
                                amount: 2000,
                                currency: 'USD'
                            }
                        },
                        {
                            _id: '00000000000003',
                            name: 'MeatOne Goasht Wala',
                            catagory: {_id: 'Meat', ancestors: ['Meat']},
                            price: {
                                amount: 20,
                                currency: 'USD'
                            }
                        }
                    ];

                    var users = [{
                        profile: {
                            username: 'shoaibhb',
                            picture: 'http://pbs.twimg.com/profile_images/364903575/ShoaibHayat_Butt.jpg'
                        },
                        data: {
                            oauth: 'invalid',
                            cart: []
                        }
                    }];

                    Catagory.create( catagories, function(error) {
                        assert.ifError(error)
                        Product.create(products, function(error) {
                            assert.ifError(error)
                              User.create(users, function(error) {
                                  assert.ifError(error);
                                  User.findOne({}, function(err, user) {

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

    it('can load a Catagory by id', function(done) {
        // Create a single Catagory
        // Catagory.create({ _id: 'Electronics' }, function(error, doc) {
        //     assert.ifError(error);
            var url = URL_ROOT + '/catagory/id/Electronics';
            //Make and HTTP request to localhost:3131/catagory/id/Electronics
            superagent.get(url, function(error, res) {
                assert.ifError(error);
                var result;
                // and make sure we got { _id: 'Electronics'} back
                assert.doesNotThrow(function() {
                    result = JSON.parse(res.text);
                });
                assert.ok(result.catagory);
                assert.equal(result.catagory._id, 'Electronics');
                done();
            });
        //});// ends here
    });

    it('can load all Catagories that have a certain parent', function(done) {

        // Create 4 catagories was here earlier, moved to beforeEach()

        //Catagory.create(catagories, function(error, catagories) {
            var url = URL_ROOT + '/catagory/parent/Electronics';
            //make HTTP request to /catagory/parent/Electronics
            superagent.get(url, function(error, res) {
                assert.ifError(error);
                var result;
                assert.doesNotThrow(function() {
                    result = JSON.parse(res.text);
                });
                assert.equal(result.catagories.length, 2);
                // should be in assending order by _id
                assert.equal(result.catagories[0]._id, 'Laptop');
                assert.equal(result.catagories[1]._id, 'Phones');
                done();
            });
        //});// create cat ends here
    });

    it('can load a product by id', function(done) {
        //Create a single product


        var oneProduct = {
                name: 'LG G4',
                _id: PRODUCT_ID,
                catagory: { _id: 'Phones', ancestors: ['Electronics', 'Phones']},
                price: {
                    amount: 300,
                    currency: 'USD'
                }
            };

        Product.create(oneProduct, function(error, doc) {
          assert.ifError( error);
            var url = URL_ROOT + '/product/id/' + PRODUCT_ID;
            // Make HTTP request to 
            // localhost:3131/product/id/0000000000000000000001
            superagent.get(url, function(error, res) {
                assert.ifError(error);
                var result = {};
                //And make sure we got LG G4 back

                assert.doesNotThrow(function() {
                    result = JSON.parse(res.text);
                });

                assert.ok(result.product);
                assert.equal(result.product._id, PRODUCT_ID);
                assert.equal(result.product.name, 'LG G4');
                done();
            });     
        });
    });

    it('can load all products in a Catagory with sub-catagories', function(done) {

        // moved to beforeEach function 

                var url = URL_ROOT + '/product/catagory/Electronics';
                //Make HTTP Request to loca:3131
                superagent.get(url, function(error, res) {
                    assert.ifError(error);
                    var result;
                    assert.doesNotThrow(function() {
                        result = JSON.parse(res.text);                
                    });
                    assert.equal(result.product.length, 2);
                    // should be assending order by name
                    assert.equal(result.product[0].name, 'Asus Zenbook Prime');
                    assert.equal(result.product[1].name, 'LG G4');

                    //Sort by price , assending
                    var url = URL_ROOT + '/product/catagory/Electronics?price=1';
                    superagent.get(url, function(error, res) {
                        assert.ifError(error);
                        var result;
                        assert.doesNotThrow(function() {
                            result = JSON.parse(res.text);
                        });
                        assert.equal(result.product[0].name, 'LG G4');
                        assert.equal(result.product[1].name, 'Asus Zenbook Prime');
                    });
                    //console.log(error);
                    assert.ifError(error);
                    done();
            });
    });


    it('can load user cart', function(done) {
        var url = URL_ROOT + '/me/';
        User.findOne({}, function( error, user) {
            console.log("error %j",error);
            //assert.ifError(error);
            user.data.cart = [{ product: PRODUCT_ID, quantity: 1}];
            console.log(user.data.cart);
            user.save(function(error) {
                assert.ifError(error);
                superagent.get(url, function(error, res) {
                    assert.ifError(error);
                    assert.equal(res.status, 200);
                    var result;
                    assert.doesNotThrow(function() {
                        result = JSON.parse(res.text).user;
                    });
                    assert.equal(result.data.cart.length,1);
                    assert.equal(result.data.cart[0].product.name, 'Asus Zenbook Prime');
                    assert.equal(result.data.cart[0].quantity, 1);

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



    it('can save user cart', function(done) {
        var url = URL_ROOT + '/me/cart/';

        superagent.put(url).send({
             data: {
                 cart: [{ product: PRODUCT_ID, quantity: 1}]
             }
         }).end(function(error, res) {
             assert.ifError(error);
             assert.equal(res.status, status.OK);
             User.findOne({}, function(error, user) {
                 assert.ifError(error);
                 assert.equal(user.data.cart.length, 1);
                 assert.equal(user.data.cart[0].product, PRODUCT_ID);
                 assert.equal(user.data.cart[0], quantity, 1);
             });
         });
         done();
    });
    enter code here

});

所以问题:

  1. 我在做什么错误
  2. 我的方法不正确
  3. mocha中是否存在我不知道的问题
  4. 就是这样
  5. 我的环境是MongoDB,Node,Express,Windows

    编辑:完整代码可在此处找到:

    D:\Programs_Insalled\nodejs\finalMEAN\edx\retailStore>mocha test-6passing.js
    
    D:\Programs_Insalled\nodejs\finalMEAN\edx\retailStore>mocha test-6passing.js
    
    
      Store API
    express-session deprecated undefined resave option; provide resave option auth.j
    s:57:39
    express-session deprecated undefined saveUninitialized option; provide saveUnini
    tialized option auth.js:57:39
        √ can load a Catagory by id (81ms)
        √ can load all Catagories that have a certain parent
        √ can load a product by id
        √ can load all products in a Catagory with sub-catagories
        √ can load user cart
    error null
        1) "before each" hook
    
    
      5 passing (752ms)
      1 failing
    
      1) Store API "before each" hook:
         Uncaught TypeError: Cannot read property 'data' of null
          at test-6passing.js:243:17
          at node_modules\mongoose\lib\query.js:1173:16
          at node_modules\mongoose\node_modules\kareem\index.js:109:16
    
    
    
    
    D:\Programs_Insalled\nodejs\finalMEAN\edx\retailStore>mocha test-6passing.js
    
    
      Store API
    express-session deprecated undefined resave option; provide resave option auth.j
    s:57:39
    express-session deprecated undefined saveUninitialized option; provide saveUnini
    tialized option auth.js:57:39
        √ can load a Catagory by id (89ms)
        √ can load all Catagories that have a certain parent (38ms)
        √ can load a product by id
        √ can load all products in a Catagory with sub-catagories
        √ can load user cart
    error null
        1) "before each" hook
    
    
      5 passing (922ms)
      1 failing
    
      1) Store API "before each" hook:
         Uncaught TypeError: Cannot read property 'data' of null
          at test-6passing.js:243:17
          at node_modules\mongoose\lib\query.js:1173:16
          at node_modules\mongoose\node_modules\kareem\index.js:109:16
    
    
    
    
    D:\Programs_Insalled\nodejs\finalMEAN\edx\retailStore>mocha test-6passing.js
    
    
      Store API
    express-session deprecated undefined resave option; provide resave option auth.j
    s:57:39
    express-session deprecated undefined saveUninitialized option; provide saveUnini
    tialized option auth.js:57:39
        √ can load a Catagory by id (96ms)
        √ can load all Catagories that have a certain parent
        √ can load a product by id
        √ can load all products in a Catagory with sub-catagories
        √ can load user cart
    error null
        √ can save user cart
    
    
      6 passing (852ms)
    
    
    D:\Programs_Insalled\nodejs\finalMEAN\edx\retailStore>mocha test-6passing.js
    
    D:\Programs_Insalled\nodejs\finalMEAN\edx\retailStore>mocha test-6passing.js
    
    
      Store API
    express-session deprecated undefined resave option; provide resave option auth.j
    s:57:39
    express-session deprecated undefined saveUninitialized option; provide saveUnini
    tialized option auth.js:57:39
        √ can load a Catagory by id (80ms)
        √ can load all Catagories that have a certain parent
        √ can load a product by id
        1) can load all products in a Catagory with sub-catagories
        √ can load user cart
    error null
        2) "before each" hook
    
    
      4 passing (862ms)
      2 failing
    
      1) Store API can load all products in a Catagory with sub-catagories:
    
          Uncaught AssertionError: 0 == 2
          + expected - actual
    
          -0
          +2
    
          at test-6passing.js:215:28
          at Request.callback (node_modules\superagent\lib\node\index.js:785:12)
          at IncomingMessage.<anonymous> (node_modules\superagent\lib\node\index.js:
    990:12)
          at endReadableNT (_stream_readable.js:913:12)
    
      2) Store API "before each" hook:
         Uncaught TypeError: Cannot read property 'data' of null
          at test-6passing.js:243:17
          at node_modules\mongoose\lib\query.js:1173:16
          at node_modules\mongoose\node_modules\kareem\index.js:109:16
    
    
    
    
    D:\Programs_Insalled\nodejs\finalMEAN\edx\retailStore>mocha test-6passing.js
    
    
      Store API
    express-session deprecated undefined resave option; provide resave option auth.j
    s:57:39
    express-session deprecated undefined saveUninitialized option; provide saveUnini
    tialized option auth.js:57:39
        √ can load a Catagory by id (86ms)
        √ can load all Catagories that have a certain parent (38ms)
        √ can load a product by id
        √ can load all products in a Catagory with sub-catagories
        √ can load user cart
    error null
        1) "before each" hook
    
    
      5 passing (744ms)
      1 failing
    
      1) Store API "before each" hook:
         Uncaught TypeError: Cannot read property 'data' of null
          at test-6passing.js:243:17
          at node_modules\mongoose\lib\query.js:1173:16
          at node_modules\mongoose\node_modules\kareem\index.js:109:16
    
    
    
    
    D:\Programs_Insalled\nodejs\finalMEAN\edx\retailStore>mocha test-6passing.js
    
    
      Store API
    express-session deprecated undefined resave option; provide resave option auth.j
    s:57:39
    express-session deprecated undefined saveUninitialized option; provide saveUnini
    tialized option auth.js:57:39
        √ can load a Catagory by id (97ms)
        √ can load all Catagories that have a certain parent (43ms)
        √ can load a product by id
        √ can load all products in a Catagory with sub-catagories
        √ can load user cart
    error null
        √ can save user cart
    
    
      6 passing (785ms)
    
    
    D:\Programs_Insalled\nodejs\finalMEAN\edx\retailStore>mocha test-6passing.js
    
    
      Store API
    express-session deprecated undefined resave option; provide resave option auth.j
    s:57:39
    express-session deprecated undefined saveUninitialized option; provide saveUnini
    tialized option auth.js:57:39
        √ can load a Catagory by id (83ms)
        √ can load all Catagories that have a certain parent
        √ can load a product by id (39ms)
        √ can load all products in a Catagory with sub-catagories
        √ can load user cart
    error null
        1) "before each" hook
    
    
      5 passing (797ms)
      1 failing
    
      1) Store API "before each" hook:
         Uncaught TypeError: Cannot read property 'data' of null
          at test-6passing.js:243:17
          at node_modules\mongoose\lib\query.js:1173:16
          at node_modules\mongoose\node_modules\kareem\index.js:109:16
    
    
    
    
    D:\Programs_Insalled\nodejs\finalMEAN\edx\retailStore>mocha test-6passing.js
    
    D:\Programs_Insalled\nodejs\finalMEAN\edx\retailStore>mocha test-6passing.js
    
    
      Store API
    express-session deprecated undefined resave option; provide resave option auth.j
    s:57:39
    express-session deprecated undefined saveUninitialized option; provide saveUnini
    tialized option auth.js:57:39
        √ can load a Catagory by id (93ms)
        √ can load all Catagories that have a certain parent (38ms)
        √ can load a product by id
        √ can load all products in a Catagory with sub-catagories
        √ can load user cart
    error null
        √ can save user cart
    
    
      6 passing (806ms)
    
    
    D:\Programs_Insalled\nodejs\finalMEAN\edx\retailStore>
    

3 个答案:

答案 0 :(得分:2)

我不会问问题的解决方案,但它解决了我的问题。我更改了beforeEach()函数,以便在每次测试之前单独处理数据的创建和删除,并使其稳定。

以下是我所做的代码。

 beforeEach(function(done) {
    // Make sure categories are empty before each test
    Category.remove({}, function(error) {
      assert.ifError(error);
      Product.remove({}, function(error) {
        assert.ifError(error);
        User.remove({}, function(error) {
          assert.ifError(error);
          done();
        });
      });
    });
  });

  beforeEach(function(done) {
    var categories = [
      { _id: 'Electronics' },
      { _id: 'Phones', 'parent': 'Electronics' },
      { _id: 'Laptops', 'parent': 'Electronics' },
      { _id: 'Bacon' }
    ];

    var products = [
      {
        name: 'LG G4',
        category: { _id: 'Phones', ancestors: ['Electronics', 'Phones'] },
        price: {
          amount: 300,
          currency: 'USD'
        }
      },
      {
        _id: PRODUCT_ID,
        name: 'Asus Zenbook Prime',
        category: { _id: 'Laptops', ancestors: ['Electronics', 'Laptops'] },
        price: {
          amount: 2000,
          currency: 'USD'
        }
      },
      {
        name: 'Flying Pigs Farm Pasture Raised Pork Bacon',
        category: { _id: 'Bacon', ancestors: ['Bacon'] },
        price: {
          amount: 20,
          currency: 'USD'
        }
      }
    ];

    var users = [{
      profile: {
        username: 'vkarpov15',
        picture: 'http://pbs.twimg.com/profile_images/550304223036854272/Wwmwuh2t.png'
      },
      data: {
        oauth: 'invalid',
        cart: []
      }
    }];

    Category.create(categories, function(error) {
      assert.ifError(error);
      Product.create(products, function(error) {
        assert.ifError(error);
        User.create(users, function(error) {
          assert.ifError(error);
          done();
        });
      });
    });
  });

答案 1 :(得分:0)

所以,这里确实没有足够的信息,但我可以告诉你要找什么。让我们从你得到的错误开始:

Uncaught TypeError: Cannot read property 'data' of null
  at test-6passing.js:243:17
  at node_modules\mongoose\lib\query.js:1173:16
  at node_modules\mongoose\node_modules\kareem\index.js:109:16

所以,第二行告诉我们错误是在test-6passing.js中,在第243行第17列引发的。所以,不幸的是,SO没有显示行号,所以我不确切知道它在哪里是,但你可以在文本编辑器中找到该行,这将告诉你错误发生时正在执行哪个函数。

第一行告诉我们您正在尝试读取对象的“data”属性,但该对象为null。假设第24行第243行的函数是Catagory.remove - 我们可以查看该函数,以准确了解测试中的null对象。然后,您必须查看为什么它是null

这有无数可能的原因。也许你拼错了Catagory.remove函数中的对象名称?也许信息还没有被填充 - javascript是一种异步语言,对于许多来自其他编程语言的人来说很难习惯。

如果这没有用,请尝试使用定义模型及其方法/功能的代码更新帖子。

答案 2 :(得分:0)

看起来您的测试不会每次都将数据库保持在相同的状态。错误在这里:

it('can load user cart', function(done) {
    var url = URL_ROOT + '/me/';
    User.findOne({}, function( error, user) {
        console.log("error %j",error);
        //assert.ifError(error);
        user.data.cart = [{ product: PRODUCT_ID, quantity: 1}];

其中user为空。也许一些测试是删除用户而另一个是添加它?