使用 mocha 调整 Nodejs 图像大小

Nodejs test image resizing with mocha

我在 nodejs 应用程序中使用 graphicmagick 调整了图像的大小。

问题是在编写单元测试时,我似乎找不到任何方向或示例。看到我正在使用第三方模块,我测试图像大小调整是否有意义?如果是,我如何为我的代码编写测试?

// dependencies
var async = require('async');
var AWS = require('aws-sdk');
var gm = require('gm').subClass({ imageMagick: true });
var util = require('util');

// get reference to S3 client
var s3 = new AWS.S3();

var _800px = {
    width: 800,
    destinationPath: "large"
};

var _500px = {
    width: 500,
    destinationPath: "medium"
};

var _200px = {
    width: 200,
    destinationPath: "small"
};

var _45px = {
    width: 45,
    destinationPath: "thumbnail"
};

var _sizesArray = [_800px, _500px, _200px, _45px];

var len = _sizesArray.length;

// handler for dev environment

exports.GruntHandler = function (filepath) {

    console.log("Path to file is: " + filepath);

    // get the file name
    var srcFile = filepath.split("/").pop();

    var dstnFile = "dst";

    // Infer the image type.
    var typeMatch = srcFile.match(/\.([^.]*)$/);
    if (!typeMatch) {
        console.error('unable to infer image type for key ' + srcFile);
        return;
    }
    var imageType = typeMatch[1];
    if (imageType != "jpg" && imageType != "png") {
        console.log('skipping non-image ' + srcFile);
        return;
    }

    for (var i = 0; i<len; i++) {

        // Transform the image buffer in memory.
        gm(filepath)
            .resize(_sizesArray[i].width)
            .write(dstnFile + "/" + _sizesArray[i].destinationPath + "/" + srcFile, function (err) {
                if (err) {
                    console.log(err);
                }
            });
    }


   console.log(" grunt handler called!");
};

编写单元测试时的惯例是只测试孤立的单元。 所有外部依赖都应该是stubbed/mocked,所以你可以只检查你单元中的逻辑(在这种情况下你的单元就是你的模块)。

至于要测试什么,你的单元唯一的public方法是"GruntHandler",所以这是你唯一应该测试的方法,因为它是本单位向其他单位提供的服务。

为了替换所有模块的依赖,我喜欢使用proxyquire包。它用您可以控制的存根替换 "require" 调用。

我已经使用我个人使用的测试堆栈编写了一个示例测试:proxyquire、mocha、用于间谍的 sinon、用于断言的 chai。

设置 - 将其放入 "test-helper" 模块以要求所有测试文件:

var chai = require('chai');
var sinonChai = require("sinon-chai");
var expect = chai.expect;
var sinon = require('sinon');
chai.use(sinonChai);
var proxyquire = require('proxyquire');

在你的测试文件中:

require('./test-helper');
describe('Image Resizing module', function () {
  var gmSubclassStub = sinon.stub();

  var testedModule = proxyquire('path-to-tested-file', {
    'gm': {subClass: sinon.stub().returns(gmSubclassStub)}
  });

  describe.only('GruntHandler', function () {
    it("should call gm write with correct files", function () {
      // Arrange
      var filepath = 'pepo.jpg';

      // Spies are the methods you expect were actually called
      var write800Spy = sinon.spy();
      var write500Spy = sinon.spy();
      var write200Spy = sinon.spy();
      var write45Spy = sinon.spy();

      // This is a stub that will return the correct spy for each iteration of the for loop
      var resizeStub = sinon.stub();
      resizeStub.withArgs(800).returns({write:write800Spy});
      resizeStub.withArgs(500).returns({write:write500Spy});
      resizeStub.withArgs(200).returns({write:write200Spy});
      resizeStub.withArgs(45).returns({write:write45Spy});

      // Stub is used when you just want to simulate a returned value
      gmSubclassStub.withArgs(filepath).returns({resize:resizeStub});

      // Act - this calls the tested method
      testedModule.GruntHandler(filepath);

      // Assert
      expect(write800Spy).calledWith("dst/large/pepo.jpg");
      expect(write500Spy).calledWith("dst/medium/pepo.jpg");
      expect(write200Spy).calledWith("dst/small/pepo.jpg");
      expect(write45Spy).calledWith("dst/thumbnail/pepo.jpg");
    });
  });
});

关于 sinon 间谍、存根和模拟的更多信息:http://sinonjs.org/

代理要求:https://github.com/thlorenz/proxyquire

还有关于所有这些的精彩教程:http://kroltech.com/2014/02/node-js-testing-with-mocha-chai-sinon-proxyquire/#.VPTS9fmUdV0