Mocking Objects in React’s Test

Michael Susanto
7 min readMay 21, 2021
Source: https://dev.to/destro_mas

This article is written as a part of Individual Review of Fasilkom UI’s Software Engineering Project Course 2021

Mock the API!

Imagine you’re currently building a Frontend Application. Nowadays, there is at least one call to an API to make your app’s content is dynamic and interesting. You’ve always done Test-Driven Development in your project and past projects, so you don’t want to miss out a single line, do you? But, how to test a function that calls API? Yes, you have to mock it. But why?

While writing tests, it is important to understand that we must not call the real API. It can slow the run time of tests and can make unwanted changes to the real API!

If you’re building a large-scale application, mocking is a good practice and a part of Test-Driven Development (TDD) in Frontend Applications. Skipping this part may take effect in the future if you find some bugs and you don’t know where the bugs are. So, mocking the function that calls an API can save us more time in the future.

What is Mocking?

Mocking means creating a fake version of an external or internal service that can stand in for the real one, helping your tests run more quickly and more reliably, for example: API calls. While writing tests, we must make sure to create single responsibility tests, one test for one function. As a result, we don’t have to test again another function which is called inside a function we’are currently testing.

Let’s take an example, there are two functions: A and B. Function B calls an external API or Service. We want to test Function A that calls Function B in it. Let’s say Function B is already tested, so that:

  • We don’t want to test Function B inside Function A.
  • We want to test Function A and expect Function B is already tested for its correctness.

In order to test Function A, we can mock the Function B and assume it gives the right output. So, we can focus to test Function A.

By mocking a function, we override them so it immediately returns the expected result. In above case, instead of predicting the output of Function B, we specify the output of Function B directly and use it to test Function A.

Mocking in ReactJS with Jest

Jest is a testing library framework for JavaScript created by Facebook. We will see a simple mocking test with Jest to test a Function that calls another Function that calls an API like the previous case above.

Suppose, we have a post function in http.js to make request / call to an API with request method POST, and have already been tested.

post function in http.js (tested)

Now, we want to test a login function that calls an API with the post function above. First, we create the test:

Create test for login function with Jest.

Here’s the explanation of the test code above:

  • We tell Jest to mock post function in http.js module with spyOn(module, function)
  • The return value of the post function is expected to be some JSON with two fields: access and refresh (because we are calling the login function to an API and expect the result to get access token and refresh token). The access represents JWT access token and refresh represents JWT refresh token.
  • Now we will test the login function which accepts one parameter, form object, contains email and password data passed by user, and calls the post function from http.js.
  • We expect the postMock (note that post function in http.js has 3 parameters) to accepts: ${AUTH_API}/token/ url, no access token (because we want to get it now with this API call), and the data passed from user. Note that we don’t call the real API here, we mocked the result of postMock to be consumed by login function in this test. We just want to verify that postMock received 3 parameters correctly from login function, and didn’t check the implementation of postMock.
  • After that, we expect that login function will have the access token and refresh token in the response.

Now, if we run the test, the test will fail because the login function isn’t implemented yet.

Test is failed because we haven’t implemented the login function yet.

Let’s implement the login function.

Implementation of login function.

Then, we run the test again.

The test is passed with 100% coverage.

Mocking Test in Software Engineering Project Course 2021

We’ve already seen a sample example of Mocking with React’s Jest. Now, for better understanding, we will look at another example from my Software Engineering Project Course 2021's Project, iAksesoris.

Suppose we want to retrieve all user’s transaction from iAksesoris’s Backend API. The difference with the previous login example is this endpoint needs Authentication. Here, we have the get function (and already tested), similar to the post function above.

get function in http.js (tested)

Now, we want to test a getAllTransactions function that calls to the API with the get function above. First, we create the test:

Create test for getAllTransactions function with Jest.

Here’s the explanation of the test code above:

  • We tell Jest to mock get function in http.js module with spyOn(module, function)
  • The return value of the get function is expected to be a list that contains JSON objects of transactions.
  • Now we will test the getAllTransactions function which accepts one parameter, access token. We need this because this endpoint is protected in the real API, so we imitate and mock the function just like the real implementation later, and calls the get function from http.js.
  • We expect the getMock (note that get function in http.js has 2 parameters) to accepts: ${AUTH_API}/token/ url, and JWT access token. Just like the previous example, we don’t call the real API here, we mocked the result of getMock to be consumed by getAllTransactions function in this test. We just want to verify that getMock received 2 parameters correctly from getAllTransactions function, and didn’t check the implementation of getMock.
  • After that, we expect that getAllTransactions function will have the list of transactions in the response.

Now, let’s run and fail the test (Test-Driven Development practice).

Test is failed because we haven’t implemented the getAllTransactions function yet.

Next, we implement the getAllTransactions function, then run the test again.

Implementation of getAllTransactions function.
The test is passed with 100% coverage.

Bonus: Mocking vs Stubbing?

Stubs and Mocks are two foundational concepts in testing that are often misunderstood. In a simply way, Stubs and mocks are both dummy objects for testing, while stubs only implement a pre-programmed response, mocks also pre-program specific expectations. In this section, I’ll demonstrate Mocking and Stubbing with Sinon.js.

For example, we will unit test an imaginary function for purchasing items in an eCommerce site. We will try to pay and get the payment status, and if we are successful we will send a mail. Here, we will see how to do the test using stub and mock.

const purchaseItemsFromCart = (cartItems, user) => {
let payStatus = user.paymentMethod(cartItems)
if (payStatus === "success") {
user.sendSuccessMail()
} else {
user.redirect("payment_error_page")
}
}

}
// Stubbing
"when purchase payed successfully user should receive a mail" : function() {
// Setup
let paymentStub = sinon.stub().returns("success")
let mailStub = sinon.stub()
let user = {
paymentMethod: paymentStub,
sendSuccessMail: mailStub
}

// Exercise
purchaseItemsFromCart([], user)

// Verify
assert(mailStub.called)
}
// Mocking
"when purchase payed successfully user should receive a mail" : function() {
// Setup objects
let userMock = sinon.mock({
paymentMethod: () => {},
sendSuccessMail: () => {}
})

// Setup expectations
userMock.expect(paymentMethod).returns("success")
userMock.expect(sendSuccessMail).once()

// Exercise
purchaseItemsFromCart([], user)

// Verify mocks
userMock.verify()
}

So, the difference in Stubbing and Mocking is just that Mocks can do whatever stubs can do, plus setting expectations directly on the objects they are faking.

My Thoughts

I think that Mocking is very beautiful, such that we can easily test API calls by mocking another function that calls the API. For example, imagine if we didn’t mock the API call to get all transactions, our test may fail if there are changes to the number of transactions in the real API. Moreover, imagine if we are making test that contains API call to modify the data in the server’s API, we just produced an unwanted data to the API.

Mocking can really help developers to focus on the correctness of specific function’s implementation, by manipulating the returned value of inner functions. With this, we can continue our TDD journey without any problems!

Thank you for reading, Happy Mocking!

--

--

Michael Susanto

Currently studying at Faculty of Computer Science, Universitas Indonesia.