Test driven development TDD best practices and notes

I was asked to discuss test driven development with our teams and did a bunch of research to share with everyone. Below is what I presented.

Focusing on unit tests, other layers of TDD is:
– regression tests (when things are changed old bugs don’t come back)
– integrations tests (multiple steps, a flow of logic)
– e2e tests (a user journey flow from start to finish)

Research the layers of tdd you could find useful tests to help add to a project’s stability.

The argument for routine

Make TDD a part of your coding routine. The initial setup of the tests might take some TLC and time, but once that is done you should rarely have to do much new development. Once TDD becomes habit it becomes easier to to do.

The below is a combination of online research, experience and advice given by Robert C. Martin in Clean Code.

The 3 laws of TDD:

1. You have to write a failing unit test before you write any code.
2. You must not write more than was is sufficient to make the test fail.
3. You must not write more production code than what is sufficient to make the test pass.

Structure of a test:

Build, Operate, Check or “Arrange, Act, Assert,” (sometimes there’s a 4th step – teardown – cleans after test ends – most frameworks should handle that for you)

1. Build / Arrange

What data do you need? What stubs should you call in? On backend you might want to create a fake model to use.

2. Operate / Act

Usually: Call a method. Or pass values into a method.

3. Check / Assert

Check the result of the Operate / Act step. Is it what you expected?

Make sure the tests are clean

Make sure you give as much thought to the quality of your tests as you do for the quality of your production code. If you let your tests rot, your code will rot.

Clean tests = readability; clarity, simplicity, density.

Guidelines:

One assert per test. Same way that in your code you look at DRY and single responsibility – if you have to assert multiple things in a test relook your code, you are probably doing too much in the actual code of method you are testing.

Test a single assertion.

FIRST

Clean tests follow with 5 FIRST rules, as mentioned in Clean Code:

Fast

– runs quickly, you don’t want to wait 10 minutes for the tests to run, no one will run the tests. The ideal situation is that the tests run continuously while you are coding.

Independent

– one test should not rely on another test running

Repeatable

– You should be able to run tests in staging, prepared, prod. You should not hard code tests to a specific environment.

Self-Validating

– No manual interpretation needed (human eyes don’t define if its passing or not)

Timely

– Should be written before your code.

Avoid

Be aware of these and avoid them

Tightly coupled tests = harder to refactor code.
Tests that depend on other tests to run.
Too many assertions in one test.
Testing other parts of the code that are outside of the method you are testing.

Remember: Test rot = code rot. Keep tests clean.

TDD should be easy and quick. The first warning sign that you are doing incorrect tests and not following best practice is if they take a lot of time.

Goal of TDD

Write tests that “have your back”.
Tests should be quick and easy.
Forces you to write neater code. Code quality goes up. Bugs go down. Rewrites become less, refactoring over rewrites.

Angular Unit Tests for Promise Chains that use .then()

A quick and simple way to test promises and then methods is to use $q.resolve()

I tried very complicated approaches including using $httpBackend, but in the end there was this very lightweight and simple solution to test promises in angular.

Use spyOn.and.returnValue and return $q.resolve() with scope.$digest()

Syntax:

1
2
3
spyOn(object, ‘method’).and.returnValue($q.resolve(data));

scope.$digest();

Data can be anything, a primitive value or an object for example.

Remember to use scope.$digest() to trigger it.

Struggling with selenium, splinter and phantomjs

If you’re trying to test with selenium and splinter, and getting failed tests in phantomjs but the tests work in chrome or firefox, try these settings:

Service arguments

browser = Browser(‘phantomjs’, service_args=[‘–ignore-ssl-errors=true’, ‘–ssl-protocol=any’, ‘–webdriver-loglevel=DEBUG’])

Maximize the window

browser .driver.maximize_window()

Or set your window size

browser .driver.set_window_size(1024, 1024)

Setup karma and jasmine for front end unit testing

Jasmine is a great unit testing tool for angular and for javascript. You have the ability to run your unit tests through chrome, firefox, phantomjs and several more.

For this post I’ll be setting up the jasmine environment to run through firefox, chrome and then the ghost browser: phantomjs.

Prerequisites

Make sure you have npm installed

Install karma and karma-cli globally (remove -g if you just want it locally)

npm install -g karma
npm install -g karma-cli

Setup your package.json file

In a new folder create your package.json file by running:

npm install init (insert your project details)

Install packages using npm

npm install karma –save-dev
npm install karma-jasmine –save-dev
npm install karma-firefox-launcher –save-dev
npm install karma-chrome-launcher –save-dev
npm install karma-phantomjs-launcher –save-dev

The –save-dev will indicate to npm that it should add this library as a dependency in your package.json file.

You will see the following content added to package.json

“devDependencies”: {
“jasmine-core”: “^2.3.4”,
“karma”: “^0.13.12”,
“karma-
chrome-launcher”: “^0.2.1”,
“karma-firefox-launcher”: “^0.1.6”,
“karma-jasmine”:
“^0.3.6”,
“karma-phantomjs-launcher”: “^0.2.1”,
“phantomjs”: “^1.9.18”
},

Add the karma configuration file

To generate your karma.conf.js file, run the following command:

karma init karma.conf.js

Then follow the following setup process:

Do you want to capture any browsers automatically?

PhantomJS
Chrome
Firefox

What is the location of your source and test file?

test/unit/**/*Spec.js

 

There is not file matching this pattern. (Add a test/unit/TestSpec.js, make sure you
have the folders test/unit set up)

Test that it runs

in your file, TestSpec.js add:

describe(‘Hello moo’, function () {
it(‘Goes baa’, function() {

});
});

Then run

karma start karma.conf.js

Phantomjs will run, then Chrome broswer will open up, Firefox browser will open up.

Karma should say:
PhantomJS 1.9.8 (Windows 8 0.0.0) is idle
Chrome 46.0.2490 (Windows 8.1 0.0.0) is idle
Firefox 41.0.0 (Windows 8.1 0.0.0) is idle
You will see in your command line: Executed 1 of 1 SUCCESS.

(If there’s no success you may have a typo in your test js file)

Done

You now have your testing environment configured.

Read about the types of tests you can write on the jasmine documentation website, http://jasmine.github.io/.