3

I've got a basic model that I am trying to write a simple unit test suite for, and I'm clearly missing something...

The code for the model looks like this:

angular.module('AboutModel', [])
    .factory(
        'AboutModel',
        [
            function () {
                var paragraphs = [];
                var AboutModel = {
                    setParagraphs: function (newParagraphs) {
                        paragraphs = newParagraphs;
                    },
                    getParagraphs: function () {
                        return paragraphs;
                    }
                };

                return AboutModel;
            }
        ]
    );

The requirement is simple: provide a getter and a setter method for the private array called paragraphs.

And here is as far as I have got with the test suite code:

describe('Testing AboutModel:', function () {
    describe('paragraphs setter', function () {
        beforeEach(module('AboutModel'));
        it('sets correct value', inject(function (model) {
            // STUCK HERE
            // don't know how to access the model, or the setParagraphs() method
        }));
    });
    describe('paragraphs getter', function () {
        // not implemented yet
    });
});

I've been doing quite a bit of google research on the web, but so far no joy.

The solution must be simple; please help!

And it might even be the case that there's a better way of implementing the Model... open to suggestions to make it better.

For anyone interested, the full source code is here: https://github.com/mcalthrop/profiles/tree/imp/angular

thanks in advance

Matt

1 Answer 1

4

You need to run a beforeEach in your test to inject the model instance and then assign it to a variable which you can then re-use through out your tests.

var AboutModel;

beforeEach(inject(function (_AboutModel_) {
  AboutModel = _AboutModel_;
}));

You can then access your getter like so:

AboutModel.getParagraphs();

I have tweaked your original model slightly as I feel it reads a little better (my preference):

'use strict';

angular.module('anExampleApp')
  .factory('AboutModel', function () {
    var _paragraphs;

    // Public API here
    return {
      setParagraphs: function (newParagraphs) {
        _paragraphs = newParagraphs;
      },
      getParagraphs: function () {
        return _paragraphs;
      }
    };
  });

And then for testing I would use a combination of the standard Jasmine tests and spies:

'use strict';

describe('Service: AboutModel', function () {

  beforeEach(module('anExampleApp'));

  var AboutModel, paragraphs = ['foo', 'bar'];

  beforeEach(inject(function (_AboutModel_) {
    AboutModel = _AboutModel_;
  }));

  it('should set new paragraphs array', function () {
    AboutModel.setParagraphs([]);
    expect(AboutModel.getParagraphs()).toBeDefined();
  });

  it('should call setter for paragraphs', function () {
    spyOn(AboutModel, 'setParagraphs');
    AboutModel.setParagraphs(paragraphs);
    expect(AboutModel.setParagraphs).toHaveBeenCalledWith(paragraphs);
  });

   it('should get 2 new paragraphs', function () {
    AboutModel.setParagraphs(['foo', 'bar']);
    expect(AboutModel.getParagraphs().length).toEqual(2);
  });

});
Sign up to request clarification or add additional context in comments.

4 Comments

Exellent! Thanks Simon. One question though: isn't the second test redundant? ie, aren't you just testing directly what you have just done?
I would like to think it's being more thorough in the tests :) The first test ensures that setting paragraphs does what we expect i.e. assigns it to the model paragraphs variable. The second test ensures it sets the paragraphs to the exact value we passed it. Some people may do this using multiple expectations in one test method, I prefer to run one expectation per test method.
Cool. Totally agree on the "one assertion per test" approach.
FYI, here are the unit tests I finished up with for this Model: github.com/mcalthrop/profiles/blob/imp/angular/test/unit/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.