DEV Community

Cover image for Test x10 faster in JavaScript with Object Mothers
Juan Otálora
Juan Otálora

Posted on • Updated on

Test x10 faster in JavaScript with Object Mothers

Object Mothers in JavaScript are overpowered, and today I'm going to explain why you should start using them in your projects, both on the front-end and back-end. (Because yes, you also need to write tests on the front-end).

Martin Fowler might not have been the first to talk about Object Mothers, but he certainly popularized them. The idea is simple: to have functions capable of returning objects for use in our tests, although they could also be used for mocks or in any file where we need fake data.

Why are Object Mothers OP in JavaScript?

Alright, let's get to the point. Why are front-end Object Mothers so cool? For several reasons:

  1. They are easy to create.
  2. They are easy to maintain.
  3. They are easy to extend.
  4. They are easy to customize.

Do you need more reasons to start using them? You should stop creating objects directly in your tests and use object mothers to improve readability (and most importantly) the speed at which you write tests. Because, let's be honest, tests are a hassle. No one enjoys writing them (even less to maintain them), but they are necessary in our code.

Let's look at an example of what we don't want to do:

describe("when A", () => {
    it("then B", () => {
        const name = "Book"
        const product = {
            name,
            price: 12.99,
            reference: "123456",
            availableToPurchase: true
        }

        const result = getNameProduct(product)

        expect(result).toBe(name)
    })
    it("then B.2", () => {
        const price = 12.99
        const product = {
            name: "Book",
            price,
            reference: "123456",
            availableToPurchase: true
        }

        const result = getProductPrice(product)

        expect(result).toBe(price)
    })
    // Please, kill me...
})
Enter fullscreen mode Exit fullscreen mode

And now an example of what we should do. First, we create a mother for Product:

export const aProduct = (partial: Partial<Product>): Product => {
    return {
        name: "Book",
        price: 12.99,
        reference: "123456",
        availableToPurchase: true,
        ...partial
    }
}
Enter fullscreen mode Exit fullscreen mode

And now we make the tests much faster, readable, and scalable.

describe("when A", () => {
    it("then B", () => {
        const name = "Book"
        const product = aProduct({name})

        const result = getNameProduct(product)

        expect(result).toBe(name)
    })
    it("then B.2", () => {
        const price = 12.99
        const product = aProduct({price})

        const result = getProductPrice(product)

        expect(result).toBe(price)
    })
    // I want to do more tests 🙂. Ok no, but you know
})
Enter fullscreen mode Exit fullscreen mode

Object Mothers and Faker.JS

If you want to take it to the next level, I recommend using Faker.JS, a library that generates random data for your tests. Yes, there might be times when your tests pass and times when they don't because of this, but if you run your tests always with the same data, we can agree that they aren't very realistic.

Here's an example of an object mother using Faker.JS:

export const aProduct = (partial: Partial<Product>): Product => {
    return {
        name: faker.commerce.productName(),
        price: faker.commerce.price(),
        reference: String(faker.number.int({ min: 1000000000, max: 1999999999 })),
        availableToPurchase: faker.datatype.boolean(),
        ...partial
    }
}
Enter fullscreen mode Exit fullscreen mode

Now your tests won't just be easier to write and maintain, they'll be running within a chaotic dataset that can help us detect issues in our code. Because that's what tests are for, to catch errors, not just to increase project coverage.

Top comments (0)