我的摩卡测试单独工作,但一次运行时失败

Posted

技术标签:

【中文标题】我的摩卡测试单独工作,但一次运行时失败【英文标题】:My mocha tests work separately, but fail when run all at once 【发布时间】:2012-12-16 07:38:33 【问题描述】:

这可能与异步代码有关,但我不确定是什么。当我将它们分开运行时,两者都通过了:mocha test/models.coffeemocha test/login.coffee

但是当我与npm test 一起运行测试时,describe 'saving another user with same username', -> 失败了。我想数据库在运行该步骤时会被清除,因此它会保存而不是产生错误,因为它应该是一个唯一值。

另外:我对这个软件测试的东西非常陌生,如果有人有任何提示,或者想批评我的公然错误,请随时给我发电子邮件(查看我的个人资料)

谢谢!!

这是我的两个测试文件(coffeescript):

/test/models.coffee

should = require 'should'
User = require '../models'

# function to find our test user, John Egbert
findJohn = (cb) ->
  User.findOne 'public.username': 'john', (err, john) ->
    throw err if err
    cb(john)

before (done) ->

  # Drop all users from database
  User.collection.drop()

  # Create our test user, his username is John Egbert
  User.create
    password: 'test123'
    public: username: 'john', done

describe 'create user', ->
  it 'should create a document that can be found', (done) ->
    findJohn (user) ->
      should.exist user
      done()

describe 'user password', ->
  it 'should NOT be stored in plaintext', (done) ->
    findJohn (user) ->
      user.password.should.not.eql 'test123'
      done()

  it 'should return true for matching password', (done) ->
    findJohn (user) ->
      user.comparePassword 'test123', (err, isMatch) ->
        isMatch.should.eql true
        done()

  it 'should return false for non-matching password', (done) ->
    findJohn (user) ->
      user.comparePassword 'wrong_password', (err, isMatch) ->
        isMatch.should.not.eql true
        done()

describe 'saving another user with same username', ->
  it 'should produce an error', (done) ->
    User.create public: username: 'john', (err) ->
      should.exist err
      done()

/test/login.coffee:

should = require 'should'
User = require '../models'
login = require '../services/login'

before (done) ->

  # Drop all users from database
  User.collection.drop()

  # Create our test user, his username is John Egbert
  User.create
    password: 'test123'
    public: username: 'john', done

describe 'login', ->
  it 'should return true for an existing username/password combo', (done) ->
    login username: 'john', password: 'test123', (err, loggedIn) ->
      should.not.exist(err)
      loggedIn.should.be.true
      done()

  it 'should return false for a bad username/password combo', (done) ->
    login username: 'john', password: 'wrong_pass', (err, loggedIn) ->
      should.not.exist(err)
      loggedIn.should.be.false
      done()

还有/models.coffee

fs = require 'fs'
path = require 'path'
mongoose = require 'mongoose'

#Connect to mongodb
#TODO: env variable to choose production/development/testing databases
mongoose.connect 'localhost', 'siglr'

models = 

for file in fs.readdirSync './schemas'
  if path.extname(file) is '.coffee'
    modelName = path.basename file, '.coffee'
    schema = require "./schemas/#modelName"
    models[modelName] = mongoose.model modelName, schema

# key is model name, value is actual mongoose model
module.exports = models

【问题讨论】:

【参考方案1】:

这里有一件事情可能会创造出让你发疯的比赛条件。删除用户集合时,您没有传递回调。我不能确定这是否会导致问题,例如在删除集合之前插入测试用户,但是这种未能正确使用回调来等待异步操作完成的模式是您的程序的秘诀以难以调试的方式行为不端。试试这个:

before (done) ->

    # Drop all users from database
    User.collection.drop (err) ->

        # Create our test user, his username is John Egbert
        User.create
            password: 'test123'
            public: username: 'john', done

第二个建议:将console.log 语句放在每个describe/before/it 的开头(第一个语句)和另一个紧接在调用done() 之前的语句,看看它们是否按照您期望的顺序出现。

【讨论】:

仍然有同样的问题,不过是个好建议。我应该学习如何使用异步库来做类似的事情嗯? 好的,我删除了我之前的评论,因为我过于热心。我编辑了我的问题并添加了models.coffee,这可能是我的问题所在。我有一种感觉,我尝试创建一个可以加载模型的对象并没有按预期工作,并且在我的两个测试需要时创建了 2 个单独的模型实例。我可能只是重构模型加载代码,直到它工作......明天! 我发现由于某种原因,当使用npm test 运行时,我在public.username 上丢失了我的索引......所以我用适当的值调用User.collection.ensureIndex() User.creates 在前面的步骤中,它可以工作。【参考方案2】:

我发现在与npm test 一起运行测试时,由于某种原因,public.username 索引被删除。但是在单独运行每个测试时保持不变。

我在test/models.coffee中更改了以下内容:

  # Create our test user, his username is John Egbert
  User.create
    password: 'test123'
    public: username: 'john', done

致以下:

  # Create our test user, his username is John Egbert
  User.create
    password: 'test123'
    public: username: 'john', ->
      User.collection.ensureIndex  'public.username': 1 ,  unique: true , (err) ->
        throw err if err
        done()

...调用ensureIndex 一个内部猫鼬函数,该函数称为when the model is compiled initially,但由于某种原因在测试的生命周期中被删除。

使用猫鼬 3.5.4

【讨论】:

原因很可能是彼得提到的,集合被丢弃而没有管理它的回调。删除一个集合会完全删除它,索引,数据,所有这些。下次插入文档时,mongo 会再次自动创建一个集合,但索引将不再存在,因为它将是一个全新的集合。管理您的回调并考虑从集合中删除所有文档而不是删除。 谢谢,使用User.find().remove 的好建议

以上是关于我的摩卡测试单独工作,但一次运行时失败的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的自动化测试在一起运行时会失败,但单独通过?

当所有测试一起运行时,Android Instrumented 测试失败

当所有单独的测试都通过时,为啥我的 Bazel 测试报告失败?

Visual Studio 中的测试单独成功,一组失败

如何以编程方式跳过摩卡中的测试?

如何在手表模式下进行任何摩卡测试之前运行全局设置脚本