摩卡测试失败但实施工作正常

时间:2014-04-30 01:15:06

标签: javascript node.js unit-testing mocha

我正在尝试编写一个使用fs.watch方法而不是watchFile方法的较新的监视模块。

到目前为止,它运行得很漂亮,但只有当我在摩卡之外运行它。我无法弄清楚为什么我的单元测试会发脾气,也许有人在这里可以吗?

这是我的班级代码:

/**
 * requirements
 */
var fs, path, events;
fs = require('fs');
path = require('path');
events = require('events');


/**
 * private
 */
var Monitor = function(directory, options) {
    this.directory = directory;
    this.options = options || {};
    (this.options.lazy && this.empty()) || this.walk(this.directory);
    this.watch(this.directory);
};
Monitor.prototype = new events.EventEmitter();
Monitor.prototype.watch = function(directory, stats) {
    var stats = stats || {};
    if (!this.directories[directory]) {
        var w = fs.watch(directory, this.options, this.justlookatit.bind(this));
    }
    this.directories[directory] = { 'stats': stats, 'w': w };
};
Monitor.prototype.directories = function() {
    if (!Object.keys(this.directories).length) {
        this.walk(this.directory);
    }
    return this.directories;
};
Monitor.prototype.files = function() {
    if (!Object.keys(this.files).length) {
        this.walk(this.directory);
    }
    return this.files;
};
Monitor.prototype.unwatch = function() {
    if (!Object.keys(this.directories).length) {
        for (var dir in this.directories) {
            dir.w.close();
        }
    }
};
Monitor.prototype.empty = function() {
    this.unwatch();
    this.files = {};
    this.directories = {};
};
Monitor.prototype.walk = function(directory) {
    var monitor = this;
    this.empty();
    fs.readdir(directory, function(err, files) {
        if (err) return;
        for (var file in files) {
            var fullname = path.resolve(files[file]);
            if (!monitor.options.filter || monitor.options.filter(fullname)) {
                fs.stat(fullname, function(err, stats) {
                    if (err) return;
                    if (stats.isDirectory()) {
                        monitor.walk(fullname);
                        monitor.watch(fullname, stats);
                    } else {
                        monitor.files[fullname] = stats;
                    }
                });
            }
        }
    });
};
Monitor.prototype.justlookatit = function(action, file) {
    var monitor = this;
    var fullname = path.resolve(file);
    if (this.options.filter && !this.options.filer(fullname)) return;
    fs.exists(fullname, function(exists) {
        if (exists) {
            fs.stat(fullname, function(err, stats) {
                if (stats.isDirectory()) {
                    monitor.watch(fullname, stats);
                } else {
                    if (monitor.files[fullname]) {
                        if (stats.mtime.getTime() > monitor.files[fullname].mtime.getTime()) {
                            monitor.emit('modified', fullname, stats);
                        }
                    } else {
                        monitor.emit('added', fullname, stats);
                    }
                    monitor.files[fullname] = stats;
                }
            });
        } else {
            if (monitor.files[fullname]) {
                delete monitor.files[fullname];
                monitor.emit('deleted', fullname);
            } else if (monitor.directories[fullname]) {
                monitor.directories[fullname].w.close();
                delete monitor.directories[fullname];
            }
        }
    });
};


 /**
 * exports
 */
exports.start = function(directory, options) {
    return new Monitor(directory, options);
};

这是我的工作外部测试代码:

var watch = require("./watch.js");
var fs = require('fs');
monitor = watch.start(__dirname);

monitor.on('added', function(file, stats) {
    console.log("Caught Added: " + file);
});

monitor.on('modified', function(file, stats) {
    console.log("Caught Modified: " + file);
});

monitor.on('deleted', function(file) {
    console.log("Caught deleted: " + file);
});

// try creating a file immediately
fs.openSync('v.md', 'w');

第一个测试文件运行得很好,我已经尝试了openSyncopen。最后,这是一个相同测试代码的版本,包含在一个超时的mocha单元测试中:

/**
 * requirements
 */
var watch, Q, fs, path, mocha, chai, assert;
watch = require('../lib/watch.js');
Q = require('q');
fs = require('fs');
path = require('path');
mocha = require('mocha');
chai = require('chai');
assert = chai.assert;

/**
 * variables
 */
var watch_directory = path.join(__dirname, './watch');


 /**
 * tests
 */
describe('test watch', function() {
    it('should create a monitor and run callbacks after fs changes', function(done) {

        // I had planned to implement promises that chained the three callbacks
        // but couldn't get one of them working in general
        var added = function(file, stats) {
            console.log("added");
            done();
        };
        var modified = function(file, stats) {
            console.log("modified");
        };
        var deleted = function(file, stats) {
            console.log("deleted");
        };

        // create our service
        var monitor = watch.start(watch_directory);

        // assert it is defined
        assert.isDefined(monitor);

        // establish a listener
        monitor.on('added', added);
        monitor.on('modified', modified);
        monitor.on('deleted', deleted);

        // here is a file name using the current date to prevent duplication during tests
        var file = path.join(watch_directory, (new Date()).getTime() + '.md');

        // let's create the file, then delete it
        fs.open(file, 'w+', function(err, fileDescriptor) {

            // this prints before console output from the watch.js's `justlookatit` method
            console.log(err);
            console.log("writing to file");

            // we probably don't want to try closing the fileDescriptor if the open failed
            if (err) return;

            // close the file descriptor
            fs.close(fileDescriptor, function() {
                // delete the file we just created
                // fs.unlink(file, function() { /* not a big deal */ });
            });
        });

        // modify a known-existing test file
        fs.open('test.md', 'w+', function() {/* we don't care about this */});

    })
});

我在监视代码的console.log(fullname)方法中使用justlookatit进行了检查,并且它会显示正确的文件名,与单元测试生成的文件名相匹配。

然而,当我运行false时,它会继续返回fs.exists。正如我所说,这意味着文件系统通知我文件存在之前存在,这实际上没有意义。因此,我尝试通过将fs.exists方法包装在setTimeout中来添加额外延迟,但这并没有改变结果。我也尝试过使用openSync和existsSync,但没有区别。

我很难过,有没有人知道为什么摩卡代码不起作用?

2 个答案:

答案 0 :(得分:0)

所以,解决方案是去散步。我回来了,再次查看代码并找出了mocha问题的原因,并发现了许多其他错误。

问题在于缺乏背景。 justlookatit方法没有上下文,并且在test.js方案中它正在观看当前目录,而mocha测试正在观看子目录。

path.resolve只接收文件名,而不是目录,因此将其与默认(可执行文件)目录合并,因此mocha的级别为test.jswatch_test.js 。它继续找不到mocha测试用例中的任何文件,因为它们都比可执行文件低一级。

我不会详细了解所有其他错误,但是当我到达我希望将其推送到网上的点时,我可能会回来并发布存储库链接。

答案 1 :(得分:-1)

您在测试结束时错过了回调return(done);。除非你打电话给那个回调,否则摩卡每次都会超时。