Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What should i test in AngularJS? [closed]

Nowadays, specially in the angularjs testing world, there are a lot of guides for made different kind of test, like Unit-testing, Midway Testing and E2E Testing, where you can learn how to made those different test to controllers, factories, etc.

The topic is, what should be testable? I can test that my module app have the controllers, directives, successfull logins, check calls to backend, etc. But What i should test?, because you can test all things, and probably its not a good practice making "easy tests".

Can someone give me any suggestions? Thank you.

like image 562
Jorge Guerola Avatar asked Feb 21 '14 12:02

Jorge Guerola


2 Answers

For a general answer you might have a look at this question.

Assuming your unit tests for angular are written in Jasmine or something similar, note that Jasmine is geared toward 'Behavior Driven Development'.

From this presentation: "Behavior-Driven-Development is about implementing an application by describing its behavior from the perspective of its stakeholders"

Another good source, but more strict (geared toward TDD or test-driven-development) is Bob Martin's Clean Code. My biggest testing takeaways:

  • Let tests be your documentation
  • Your tests free you to refactor
  • Test close to the user or consumer and work your way inward if needed

That is to say,

  • comments can get outdated, but unit tests MUST respond to change in order to pass. This is especially relevant if you are writing with respect to specific user scenarios as BDD suggests.
  • if you think of your tests as a summary of requirements, any time you make code changes for a new feature and run your test suite, you will know instantly whether your code still meets requirements.
  • Private helper methods, return types, and data structures can change frequently. A user or consumer doesn't care about these, only that, for a given set of inputs, they get a certain effect or return.

examples:

As a rough example, suppose you have a requirement for an application that polls weather forecast data for a given city. Your user or client code's requirement could be phrased something like "Given a set of weather data, when I enter a city name I should get 5 days' forecast data". You might then have a test like:

  describe('Given a set of weather data'....
      ...
      describe('when I enter Los Angeles', function() {
          it('should return 5 days of forecast data for Los Angeles', 
          mocks.inject(function(weatherService) {
          var result = weatherService.getForecast('Los Angeles');
            expect(result.DayToForecast.lenth).toEqual(5);
          }));
      });
      ...

Then suppose you have another requirement that the weather data say something about humidity, e.g "Given a set of weather data, When I enter a city name and day I should get humidity data"

      ...
      describe('When I enter Los Angeles and Monday', function() {
          it('should return humidity data for Los Angeles on Monday', 
          mocks.inject(function(weatherService) {
          var result = weatherService.getForecast('Los Angeles');
            expect(result.DayToForecast['Monday'].humidity).not.toBe(null);
          }));
      });
      ...

Here we don't really care about the structure of the result, only that it in some way gives a notion of humidity on monday. We don't really care about the insides of weatherService either (e.g. if it gets data from a database, static file, or other web service). You might have something like this instead, but the requirement is still expressed:

      ...
      describe('when I enter Los Angeles and Monday', function() {
          it('should return humidity data for Los Angeles on Monday', 
          mocks.inject(function(weatherService) {
          var result = weatherService.getForecast('Los Angeles','Monday');
            expect(result.humidity).not.toBe(null);
          }));
      });
      ...

The cool thing here is that you can 'code by wishful thinking' -- you create function signatures close to your users and use cases and then fill them in, getting only what you need. AND now if your first requirement changes to say, "Given a set of weather data, when I enter a city name I should get 4 days' forecast data", you must change the test rather than searching for comments, and you will only need to change code that relates to that requirement change.

Some of your behaviors may not be explicitly stated by your users. For example, with respect to the example above, an end-user would be less likely than a web service consumer client to say: "Given a set of weather data, When I enter a city name and a fictional day I should get an exception" You'll have to glean that and the test case yourself:

      ...
      describe('when I enter Los Angeles and EigthDay', function() {
          it('should throw an exception', 
          mocks.inject(function(weatherService) {
          var weatherServiceCall = function(){
                weatherService.getForecast('Los Angeles','EighthDay');
              };
              expect(weatherServiceCall).toThrow();
          }));
      });
      ...
like image 152
ossek Avatar answered Nov 15 '22 07:11

ossek


You should ideally test everything.

I normally try to write unit-tests before/as I am coding. This is to ensure that code I'm writing meets some some minimum specification - that it gives the outputs I intend it to. Your unit tests should also be run in other sections as a sort of pre-integration test - have I broken something in another part of the code in making this change? In this fashion, unit tests are providing a first gateway into the program.

Note that in writing unit tests, they mean very little to what is experienced by the user. Maybe the site is functionally OK within the theoretically scope of your unit tests, but maybe they, under certain conditions, drastically affect the experience of the users? Maybe one of your features you have added reduces page load speeds? or breaks the UI in some unforeseen way. Your unit tests might not pick up on this.

Year Of Moo has a good overview of different types of angularjs testing here -http://www.yearofmoo.com/2013/01/full-spectrum-testing-with-angularjs-and-karma.html

You should also read up on continuous integration testing - this will give you some idea of how large projects test and integrate code to ensure it meets quality guidelines and doesn't break existing code. In large projects, almost everything is expected to have corresponding unit tests.

Think of testing as a pipeline

  • Does it work to the initial design?
  • Does it break any other code?
  • Does it work in the wider context of the application?
  • Does it impact the user experience?

Now, if you're trying to prioritise what to test - test anything you think is sufficiently complicated with unit tests, and try to write E2E test scenarios that cover as much as possible. If you find your E2E tests are failing a lot, that would be a hint that you need more unit tests, because your uncovering a lot of edge cases/undefined behaviour that you may not be aware of.

You should definitely be writing unit tests for controllers and directives, as they form the lions share of your application and usually define your business logic.

like image 38
Matthew Tyler Avatar answered Nov 15 '22 07:11

Matthew Tyler