How to mock properly the services in AngularJS

//English



As you may know, there's a lot of posts about how to create unit tests in AngularJS, you can find a lot of results in Google, but after a long time working with Angular I found that those posts are incomplete! why? simple, they tell you how to test controllers but each post I read tell you to inject the needed services, this is wrong because what happen if the service is incomplete or maybe someone introduce a bug on the latest commit? then that unit test will fail and it will fail not because the functionality to test is failing, it will fail because a dependency that we can mock...

Let's take this controller as example:


As you can see, the controler will fetch the new values from the server, following the good practices that Ajax call will be stored in a factory or service, so the controller will do what a controller should do: just be the "glue" between the view and the model :)

Now how the unit test will look like:


Now you see my point? There's no myService, it does not exist yet, this is a typical problem when you work in teams (what we normally do) meanwhile someone is working on the controller, another guy is working on the service.

If we try to run that test against our previous code, you know what will be the result: the test will fail! because there's no provider for myService. Then you have the following options to fix this issue:

  • Wait for your partner, so the provider will exist
  • Use the spy API of Jasmine (If you are using Jasmine)
  • Use Sinnon in case you're using Moca or some other Test runner different from Jasmine
Not too much choices, right? obviously we can't wait for our partner to finish, because the client always wants the product ready as soon as possible, so we need to choose: If we use an spy of Jasmine or Sinnon...In my experience, both are really good, but they are too complex for the solution we want. We don't want to test what happen inside that service neither we want to track that function. What we want is: Mock the service to see if the controller is able to reload the values!

That's the main purpose of the unit tests, test pieces of code separately, to see if they work, if we want to track the complete process: see if the service is pointing to the proper endpoint and if the service responds with the closest data to production and if the controller updates the values with that data, then we need to do an Integration Test not Unit.

But, don't worry, there's always another option: Let's mock manually that service, how? well we know that service return a promise and we know the promises take 2 callbacks as parameters: the first one will be executed in case the endpoint responds with a successful response and the second one will be executed in case the endpoint responds with a failing response. With this information we can create a good working mock, see the following test:


In the above example you can see that I create a function called serviceMock, that function will be our "provider", it will give us the object that we need to test: we need an object which has a function called: getValues and that function need to return an object with the function: then which is going to take 2 parameters and depending on the situation, the function: 'then' will execute one of them.

If we think in the above paragraph for a moment, that's all we need to test our controller, we can test both scenarios: if the service is working or if the service is failing. The code is easy to understand, we don't need to include external libraries as Sinnon nor we need to use spies which are too complex, at least for scenarios like this.

Well guys that's it for today, please let me know your thoughts and questions, either through Twitter or here ^_^/ bye!


//Español

Muy Pronto...

Comments

Popular posts from this blog

Juego de Gato Usando HTML, JavaScript y CSS

AfterEffects - Quitar el Fondo de un Video Forma 1: KeyLight

Crear un nuevo Libro de Excel con VBA ES