简体   繁体   English

如何使用mocha和should.js和sails.js编写二进制下载测试?

[英]How do I write a test for a binary download using mocha and should.js with sails.js?

I'm trying to write at test for a Sails.Js controller action that downloads a user's avatar image. 我正在尝试在测试时编写一个Sails.Js控制器动作来下载用户的头像图像。 The controller action looks like this: 控制器操作如下所示:

/**
* Download avatar of the user with the specified id
*
* (GET /user/:id/avatar)
*/
avatar: function (req, res) {

  req.validate({
    id: 'string'
  });

  User.findOne(req.param('id')).exec(function (err, user){
        if (err) return res.negotiate(err);
        if (!user) return res.notFound();

        // User has no avatar image uploaded.
        // (should have never have hit this endpoint and used the default image)
        if (!user.avatarFd) {
          return res.notFound();
        }

        var SkipperDisk = require('skipper-disk');
        var fileAdapter = SkipperDisk(/* optional opts */);

        // Stream the file down
        fileAdapter.read(user.avatarFd)
        .on('error', function (err){
          return res.serverError(err);
        })
        .pipe(res);
    });
}

So far the test looks like this: 到目前为止测试看起来像这样:

describe('try to download a user avatar', function() {
    var result;
    it('should return 200', function(done) {
        server
            .get('/user/' + testUser.id + '/avatar')
            .expect(200)
            .end(function(err, res) {
                if (err) return done(err);
                result = res.body;
                return done();
            });
        }
    }
    it('should return binary data stream', function(done) {
      // make some assertions.
    });
});

I want to add another test to make sure that what has been returned is binary data, but I can't figure out how this would be done. 我想添加另一个测试,以确保返回的是二进制数据,但我无法弄清楚如何做到这一点。 Anyone know the right way to go about this? 有人知道正确的方法吗?

UPDATE UPDATE

After attempting a solution in the mode that @sgress454 suggested below, I ended up with this test: 在以下建议的@ sgress454模式下尝试解决方案之后,我最终得到了这个测试:

tmp = require('temporary'); 
  // https://github.com/vesln/temporary

// Write nonsense bytes to a file fixture.
var EOF = '\x04';
var size = 1000;
var fileFixture = new tmp.File();
fileFixture.writeFileSync(crypto.pseudoRandomBytes(size) + EOF);
fileFixture.size = size;

after(function() {
fileFixture.unlinkSync();
});

describe('try to download a user avatar', function() {
    var download;
    it('should return 200', function(done) {
        server
            .get('/user/' + testUser.id + '/avatar')
            .expect(200)
            .end(function(err, res) {
                if (err) return done(err);
                download = new Buffer(res.text, 'ascii');
                return done();
            });
        });
    it('should return binary stream', function(done) {
        var testAvatar = fs.readFileSync(fileFixture.path);
        download.toString('base64').should.be.equal(testAvatar.toString('base64'));
        done(); 
    });
});

So this test mocks up a file using temporary . 所以这个测试使用临时模拟文件。 The trouble is that when I compare the result I get back from the server and the mock file that I'm reading from the mocked file system, they aren't the same. 麻烦的是,当我比较结果我从服务器和我正在从模拟文件系统读取的模拟文件时,它们不一样。 I get the following as expected: 我按预期得到以下内容:

  +bEk277+9azo277+916jvv71g77+9KO+/vV/vv71577+977+9U8e9A++/ve+/vSgiF++/ve+/vWsi77+977+9BRRs77+977+977+9bO+/vSoGRW3vv73vv73dr++/ve+/vXEAIFbvv70p77+977+9WMuSSm/vv73vv71W77+977+9LULvv70J77+9eFfSoVsW77+977+9QAleLgDvv71T77+9de+/vRHvv71qyJPvv73vv73vv73vv73vv71S77+91L4sf++/vQHaiicDKXXvv71977+9NO+/vUzvv71YXe+/vTjvv70n77+9fWvvv73vv709YgoW77+9bmF/77+9JNK4LO+/vUNdNGjvv70TZMazS+2IjBdgL++/ve+/vRXvv71S77+977+9SHHvv70QY++/vSbvv70SC2US77+9eGnvv71cczVOFBp7fu+/ve+/ve+/ve+/vWTvv70B77+9cm/vv73vv73vv73vv70q77+977+9JSxY77+9TO+/vQbvv73vv71sREl+Qyrvv70JFXgSHBLvv71v77+977+9AkBPOwvvv73vv73vv71R77+9VSHvv71DZ2NB77+977+977+977+9Pu+/ve+/vcabMe+/ve+/ve+/ve+/vUFnXFJP77+977+977+977+9G1/vv73vv73vv71OQe+/ve+/vdmU77+9B++/vUts77+9Zu+/vS9uUH3vv73vv73vv71y77+9PlRXSSJ3UHHvv73vv71SBXvvv73vv70677+977+9dk5O77+9de+/vTzvv70Y77+9cmjvv73vv73vv73vv712UNC0WW7vv73vv71lZD4+77+9U++/vR4MNW8RY37vv70ZTUo2fl0sKu+/vUN/bipyPO+/vSrvv73vv73vv700Bjwa77+977+9RH8A77+977+977+9zrDvv73vv70JQ2tOKe+/vV7Mk2Hvv73vv73vv70L77+9Tu+/vQwPK++/ve+/ve+/vVTvv73vv70M77+977+9Zs2/Vu+/vXzvv73vv73vv71a77+977+977+9Au+/vSrvv73vv70S77+977+9eO+/ve+/vVFk77+977+9Jm4L77+977+9fVnRl05x77+9ai1SSDZiX2fvv73vv73vv73vv73vv73vv73vv73vv71Y77+977+977+9VFvvv71B77+9X++/vTbvv70w77+977+9TO+/vSQBMB4+77+977+9Z++/vTDvv73vv71/77+977+9Dnd9Be+/vUZCehYuFu+/vVfvv73vv73vv73vv73vv73vv70+HO+/ve+/ve+/ve+/ve+/vSgLVitLQO+/ve+/vUZP77+977+977+9adWy77+977+9H++/ve+/vWTvv71677+93Zzvv73vv73vv71t77+977+977+9BGMkIFkYSxRW77+977+977+9Ke+/vRoN77+9f9CIUXQXWu+/vSYp77+9VDPvv71fLAxU77+977+977+9N++/vTbvv73vv73vv71dIjzvv73vv73vv71Z77+977+9He+/ve+/vWd6LO+/vQDvv70Bae+/vRQZ77+977+90YLvv717Ji3vv716Bu+/ve+/ve+/vVpU77+9aO+/ve+/vWnvv73vv70u2a/vv73vv73vv71p77+9WiAh77+9JyLvv73vv73vv73vv71QIUzvv71pypRO77+9Fe+/vQ7vv70Z77+9Se+/vUHvv73vv73vv70tA++/vSjvv73vv73vv73vv716K8e677+977+977+977+9Zyjvv73vv71U77+9Oe+/vRcF77+9Ku+/ve+/ve+/ve+/vVl777+9ewUAUu+/ve+/ve+/vUV/GGA6fu+/ve+/vVfvv705BA50D++/vSrvv73vv73vv71d77+977+977+977+9KO+/ve+/vUBzbO+/ve+/ve+/ve+/vXUnPS7vv71gCe+/vQ/vv70d77+9P00d77+9Tx8cOz8ABe+/vRbvv70t77+9IO+/ve+/ve+/ve+/ve+/ve+/vSQt77+9GE7vv73vv73vv73vv73So++/vVTvv71BEgDvv73vv70BdRYeTO+/vTjvv71+Ku+/vXjTu++/ve+/ve+/vRQK77+9Su+/vTvskJB/b1dyU++/ve+/vW7vv71k77+9Pu+/ve+/ve+/ve+/ve+/vVk277+9Pyfvv73vv73vv70mXO+/ve+/ve+/ve+/ve+/vQIr77+9QO+/vS1nAyXvv73vv713Ve+/vVTvv70VcV5m77+9M++/ve+/ve+/vWUx77+9OT1g77+9MQnvv71N77+977+977+9byjvv73vv71W77+977+9x5rvv70PBO+/ve+/ve+/ve+/ve+/ve+/ve+/vQd0Ru+/ve+/vU1zG++/vW5W77+977+9ES9udy3vv71CbGpVDgXvv71977+977+9QhLvv71xfnEN77+9KzDvv70KKO+/vVDvv70E 

And the following as the actual response: 以下作为实际回复:

  -bEk2/Ws6Nv3o/WD9KP1f/Xn9/VP9A/39KCIX/f1rIv39BRRs/f39bP0qBkVt/f1v/f1xACBW/Sn9/VjSSm/9/Vb9/S1C/Qn9eFehWxb9/UAJXi4A/VP9df0R/WoT/f39/f1S/T4sf/0BiicDKXX9ff00/Uz9WF39OP0n/X1r/f09YgoW/W5hf/0kuCz9Q100aP0TZLNLDBdgL/39Ff1S/f1Icf0QY/0m/RILZRL9eGn9XHM1ThQae379/f39ZP0B/XJv/f39/Sr9/SUsWP1M/Qb9/WxESX5DKv0JFXgSHBL9b/39AkBPOwv9/f1R/VUh/UNnY0H9/f39Pv39mzH9/f39QWdcUk/9/f39G1/9/f1OQf39VP0H/Uts/Wb9L25Qff39/XL9PlRXSSJ3UHH9/VIFe/39Ov39dk5O/XX9PP0Y/XJo/f39/XZQNFlu/f1lZD4+/VP9Hgw1bxFjfv0ZTUo2fl0sKv1Df24qcjz9Kv39/TQGPBr9/UR/AP39/bD9/QlDa04p/V4TYf39/Qv9Tv0MDyv9/f1U/f0M/f1mf1b9fP39/Vr9/f0C/Sr9/RL9/Xj9/VFk/f0mbgv9/X1ZV05x/WotUkg2Yl9n/f39/f39/f1Y/f39VFv9Qf1f/Tb9MP39TP0kATAePv39Z/0w/f1//f0Od30F/UZCehYuFv1X/f39/f39Phz9/f39/SgLVitLQP39Rk/9/f1pcv39H/39ZP16/Vz9/f1t/f39BGMkIFkYSxRW/f39Kf0aDf1/CFF0F1r9Jin9VDP9XywMVP39/Tf9Nv39/V0iPP39/Vn9/R39/Wd6LP0A/QFp/RQZ/f1C/XsmLf16Bv39/VpU/Wj9/Wn9/S5v/f39af1aICH9JyL9/f39UCFM/WmUTv0V/Q79Gf1J/UH9/f0tA/0o/f39/Xor+v39/f1nKP39VP05/RcF/Sr9/f39WXv9ewUAUv39/UV/GGA6fv39V/05BA50D/0q/f39Xf39/f0o/f1Ac2z9/f39dSc9Lv1gCf0P/R39P00d/U8fHDs/AAX9Fv0t/SD9/f39/f0kLf0YTv39/f2j/VT9QRIA/f0BdRYeTP04/X4q/Xj7/f39FAr9Sv07EH9vV3JT/f1u/WT9Pv39/f39WTb9Pyf9/f0mXP39/f39Aiv9QP0tZwMl/f13Vf1U/RVxXmb9M/39/WUx/Tk9YP0xCf1N/f39byj9/Vb9/dr9DwT9/f39/f39B3RG/f1Ncxv9blb9/REvbnct/UJsalUOBf19/f1CEv1xfnEN/Ssw/Qoo/VD9BA== 

I'm not sure why the files would be different at this point. 我不确定为什么文件会在这一点上有所不同。 Perhaps the problem is in the way I'm parsing the data that comes back? 也许问题在于我正在解析返回的数据?

This is one of those cases where the most obvious solution is the best: use the controller action to download a known file in your test, then load that same file from disk within the test and compare it to the one that was downloaded. 这是最明显的解决方案是最好的情况之一:使用控制器操作在测试中下载已知文件,然后在测试中从磁盘加载相同的文件并将其与下载的文件进行比较。 You'll save an avatar file in your test directory somewhere (perhaps under a fixtures subdirectory), and make sure that before your test runs, a user is created whose avatarFd points to that file. 您将某个头像文件保存在某个地方的测试目录中(可能位于fixtures子目录下),并确保在测试运行之前创建一个用户,其avatarFd指向该文件。 Then, the easiest (least efficient) way to do the second test is to just leave your first test as-is, and re-run the request: 然后,进行第二次测试的最简单(最低效)方法是按原样保留第一个测试,然后重新运行请求:

it('should return binary data stream', function(done) {
    server
      .get('/user/' + testUser.id + '/avatar')
      .end(function(err, res) {
          if (err) return done(err);
          result = res.text;
          var testAvatar = require('fs').readFileSync(pathToTestAvatar);
          assert.equal(testAvatar.toString(), result.toString();
          return done();
      });
});

Note the reference to res.text instead of res.body --since you're not specifying a content-type header for the response in your controller, Supertest makes no assumptions and just adds the raw data to the text field in the response. 请注意对res.text的引用而不是res.body因为您没有为控制器中的响应指定content-type标头, res.body不做任何假设,只是将原始数据添加到响应中的text字段。 If you put a res.set("content-type", "image/jpeg"); 如果你放一个res.set("content-type", "image/jpeg"); in the controller, for example, then the response body in your test would be a Buffer with the image bytes in it. 例如,在控制器中,测试中的响应body将是一个缓冲区,其中包含图像字节。

When I want to run separate tests on the result of a request, I tend to do the request itself in a before function, then save the body and statusCode in closure-scoped variables as you started to do here. 当我想对请求的结果运行单独的测试时,我倾向于在before函数中执行请求本身,然后在开始执行时将bodystatusCode保存在闭包范围的变量中。 Then you can run individual it tests for things like the status code, body contents, etc. So my whole test would look something like: 然后,你可以单独运行it的东西喜欢的状态代码,正文内容等测试,这样我的整个测试看起来是这样的:

var assert = require('assert');
var path = require('path');
var server = require('supertest');
var fs = require('fs');

describe('try to download a user avatar', function() {
    var result, status;
    var testAvatarFd = path.resolve(__dirname, '..', 'fixtures', 'test.jpeg');

    // Create the user and make the request before running the actual tests.
    before(function(done) {
      // Create a test user
      User.create({
        avatarFd: testAvatarFd
      }).exec(function(err, testUser) {
        if (err) {return done(err);}

          // Then request the user avatar from the server
          server(sails.hooks.http.app)
          .get('/user/' + testUser.id + '/avatar')
          .end(function(err, res) {
              if (err) return done(err);
              // Save the result in our closure-scoped variables
              result = res.text;
              status = res.statusCode;
              return done();
          });
      });
    });

    // The status code test is now synchronous
    it('should return 200', function() {
      assert.equal(status, 200);
    });

    // As is the file test, since we're using `readFileSync`
    it('should return binary data stream', function() {
      var testAvatar = fs.readFileSync(testAvatarFd);
      assert.equal(testAvatar.toString(), result.toString());
    });
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM