FactoryBoy is a Meteor package that implements a minimalistic factory for objects and Mongo documents. There are already some other factory packages out there. Yet, I decided to make this one to help me write tests more easily.

The source code for the package is available on GitHub repo.

Why another factory package?

I have been using dburles:factory to generate data while running tests. While it gets its job done, there are some things that make testing hard.

  • Factory.build returns an object with a stubbed _id.

This means that you have to manually rid the object of _id property if you just want a plain javascript object.

In my mind, when you build something with a factory, the factory should just build it, and return the result. Not only stubbing _id is an extra work, but also it makes things complicated for users.

Let’s compare the following examples of tests. One written with dburles:factory, and the other with FactoryBoy.

  // Using dburles:factory
  it("creates a post", function(){
    var post = _.omit(Factory.build('post'), '_id');

    Meteor.call('submitPost', post);
    expect(Posts.find().count()).to.equal(1);
  });

  // Using FactoryBoy
  it("creates a post", function(){
    var post = FactoryBoy.build('post');

    Meteor.call('submitPost', post);
    expect(Posts.find().count()).to.equal(1);
  });

Since FactoryBoy.build returns a plain object, it is much easier to do database operations using the result than it is with Factory.build.

  • A bug with setting nested _id.

At the time of writing this, you cannot set a nested _id using dburles:factory.

Factory.define('myColection', MyColection, {
  name: 'something'
  owner: {
    _id: 'testOwnerId',
    name: 'testOwnerName',
  },
});

If you call build of create for that factory, you will get an exception that you cannot set _id. If you have some denormalization in your database and have _id property nested somewhere, this is a problem.

Minimalistic factory

FactoryBoy resembles deburles:factory in many ways, but it solves the problems listed above by being minimalistic.

This means that it does not stub _id while building a document, or do a complicated walk on the nested objects, causing _id exception with Mongo.

Use case

Here are some examples of writing tests using FactoryBoy and Mocha.

First, you can build a plain object and do things with it.

describe("submitPost", function(){
  it("creates a post", function(){
    var post = FactoryBoy.build('post');

    Meteor.call('submitPost', post);
    expect(Posts.find().count()).to.equal(1);
  });
});

You can also set up test data using FactoryBoy.create.

it("can update a episode name", function(){
  var episode = FactoryBoy.create('episode', {
    name: 'The Gang Broke Dee'
  });

  Meteor.call('updateEpisodeName', episode._id, 'Charlie Rules the World');

  var updatedEpisode = Episodes.findOne(episode._id);
  expect(updatedEpisode.name).to.equal('Charlie Rules the World');
});

Conclusion

It is working great for me at the moment. In the future, I plan to add support for before and after hooks, and an optional argument to switch pre-defined attributes on runtime.