Example Code
describe('The service', function () {
var myService = undefined;
beforeEach(function() {
module('myApp');
inject(function (_myService_) {
myService = _myService_;
});
});
afterEach(function(){
myService = undefined;
});
it('should exist', function() {
expect(myService).not.toBeUndefined();
});
describe('truthy value', function() {
it('should be true', function () {
//arrange
var truthy = true,
returnedValue;
//act
returnedValue = myService.returnTruthy();
//assert
expect(returnedValue).toBe(truthy);
});
});
});
describe()
and it()
The first thing in your spec should be a describe
function. describe
functions hold a collection of tests together in a related way. Within each describe
you'll have one or more it
function. Each it
tests a single piece of functionality. The way that the functions are written helps you to make sure that you are grouping correctly, and testing one piece of functionality per it
.The first parameter of both the
describe
and it
functions is a string that is concatenated and used to print out a human readable description of whether each test has passed or failed. Every describe
that you have should be the beginning or middle part of a sentence and your it
should be the end part of a sentence.When you come to do more complex testing you want to think about implementing nested
describe
functions. The concept of how to structure describe
and it
functions is quite tricky to grasp in the beginning. Once this is understood it opens up the power of nesting correctly so that there can be automated reporting of test results to stakeholders or the customer in a way that they can understand without needing any technical knowledge.A test for making sure a form exists on the page when the page firsts load may write out (in human readable form) as The registration page should have a registration form present. In this statement The registration page would be your
describe
function, and should have a registration form present would be your it
function. Then you may want to test that when the user interacts with the page somehow that something else happens. Continuing this example, you may want to check that the form validates fields properly, so your sentence would be The registration page when the user submits the form should validate an email has been entered correctly. So, within the first describe
function you would add another describe
function with when the user submits the form as it's first parameter, then within that you could have multiple it
functions, one of which checks the email validation and is labelled should validate an email has been entered correctly. All of your describe
functions must be the beginning and middles of sentences and all of your it
function statements must start with should and be the end of the sentence. These rules are not constrained in any way, but if you stick to them then you'll find yourself heading in the right direction both with the semantics for print out, and for the level of complexity that you're testing.The second parameter of each of these functions is a function. This is where the similarity between the two functions ends.
It is important to remember at this stage that JavaScript has functional scope. This means, that anything declared within {braces} can be accessed by anything else within those same {braces}.
describe()
The second parameter for the describe
function is a function that contains all the code to run the tests covered by the describe
's grouping statement from the first parameter.The majority of the function calls within any
describe
will be the it
functions that contain the assertions you're making about your code. However, there may be things that you need to setup or teardown before and after each test. Rather than clogging up your it
functions with the same repeated code you can use the beforeEach
and afterEach
functions.Also within
describe
functions you might declare variables that are to be used in a global manner throughout subsequent function calls, such as variables that are manipulated by a beforeEach
or afterEach
function and then used within it
functions.
it()
The second parameter for the it
function is a function that contains the code that sets up and evaluates the set of assertions that are made to decide whether or not the test has fulfilled the description in the first parameter of the it
function. I like to use the arrange, act, assert design pattern for writing these as it helps to keep things clear and tidy.
beforeEach()
and afterEach()
These functions are beautifully self-descriptive. Any code that is written within the beforeEach
function will be run before each and every it
function within the parent describe function. Likewise, the afterEach
function is run after each and every it
function is run.I use the
beforeEach
function to establish the initial state of variables, include my AngularJs module(s), to inject any services that I may need for testing, etc. There's plenty that can be done inside of here. I use the afterEach
function less often, but when I do I typically do delete things; I reset any variables to undefined
or some specific null state. This just makes sure that nothing is leaking from one test to another so as to not cause any false passes or false fails.There are also
beforeAll
and afterAll
functions that run once before and after all the it
functions have run. I'm wary of these functions. I'm sure that they can be used effectively if used carefully, but I really dislike things that need to be used carefully.Arrange, Act, Assert
Within eachit
function I find it useful to break the space into three areas; arrange, act, and assert. This is a nice pattern that indicates the three stages of each test. If you have more than a few lines in any one of these sections it indicates that my test isn't as concise as it should be, or that I could be testing more than one thing.Arrange
In the arrange section I prepare any variables that are needed to either pass to the piece of code that I'm testing (typically function parameters), or that I want to compare to the returned value. I also set up anything that I'm mocking, or spies that are checking that particular pieces of code have been called.Act
This is where the code that is being tested is called. It really should only be one line of code.Assert
This is where all the actual tests, the assertions, live. In Jasmine we haveexpect
functions that allow other functions (known as matchers) to be chained after them to test the returned result is what was expected, or check that spies saw what they were meant to see. These return booleans, and for the it
function to pass all expect
chains need to return true.
No comments:
Post a Comment