A few tips when creating factories with FactoryBot (formally FactoryGirl).

“Base” Factory

For most DB-backed models in your system, you will want to create a “base” factory. It is what you will generally use when you need an instance of a model but don’t generally care about the data (other than the data you supply).

The factory should be named after the object you are creating it for. If your object is named then your “base” factory should be named . Your “base” factory should use the following rules:

  • Provide the minimum values necessary to be able to save a valid instance.
  • Optional fields or fields with default values are not generally provided.
  • associations should be provided assuming they are required (the default in Rails)
  • If , or records are required for your object to function you may need to populate those, but you should try to avoid your object having that sort of dependency.

Random Values

Anytime you need a value in a factory it is best to use a realistic but always changing value. For example, if I wanted to provide the age of a user I wouldn’t hard-code it to . I would use . This would make it pick a random value between 1 and 110 each time I get an instance of that factory.

The reason for using changing values is to ensure your tests don’t happen to pass due to some chance value. Each time you run your test you are introducing a bit of randomness to ferret out issues that may depend on certain values.

If you need realistic values for common needs (company names, emails, etc) I suggest libraries like forgery or faker.

Locate Important Values in Tests

If the value in an object is important for making the test pass, it should be initialized in the test. This helps to prevent your factories from becoming brittle. You want to avoid the situation where changing a factory in trivial ways breaks tests.

For example, if you have a method on your object that you are testing which combines your and your tests should look like:

With the above, your tests will not fail regardless of how your factory is configured for and . While you could have fixed values of and in the factory and not have to provide them in your test, specifying the values in the test reduces the fragility of your test suite.

If creating an object with your desired attributes is too complicated to do inline, create a specialized factory but make sure the factory name indicates it has the state you want. For example your “base” factory for your object probably won’t have line items, but some tests need a complete order. A realistic complete order does have at least one line item as well as other info (payment, shipping, etc). In this case you probably want to make a factory called that gives you a realistic completed order.

By naming it the implied attributes and related records associated with that name do not make the factory fragile as the name becomes a contract between the test and the factory.

Avoid Factory Proliferation

It can be tempting to create a child factory for every possible type of object you might need. For example, you might initially think to have your “base” factory choose a random valid permission level. But then create other factories for each role ( , , , etc.).

Instead, avoid creating a sub-factory for setting trivial attributes. If you can do just as easy in your test do that instead. It might require a few extra characters but:

  • It keeps your factories more manageable
  • It makes it clear just by looking at the test what you are doing without having to go look up what actually means.

Even for a more complex factory type if you are only using it in the scope of one test file perhaps you can just place it in a RSpec declaration.

Software Developer. Primary love is Rails.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store