The fundamentals of testing

A Blog Post by

This is the summary and notes from my talk at the JHB Drupal meetup this this month. It’s the first of a 3 part talk I’m doing on testing.

This is a very top level view of the concepts behind testing your code, as language/framework agnostic possible.

The Joke.

Developer: There is no I in TEAM

Tester: We cannot spell BUGS without U

So why test?

1. Instant feedback and gratification

Testing allows you to instantly try out your code and see if it’s working as expected.

2. Reduces bugs in new features

Writing test allows you to trap bugs in new features quicker, while ensuring that new features don’t break existing code.

3. Allows for big changes quickly

Refactoring code to align with tests allows you to quickly consider all the use cases. Think: “Refactor without fear”.

4. Leads to a better design

Code that is tightly coupled or requires complex initialisation is hard to test. So making code test-friendly, will allow for better readability and will be less error prone. Writing tests first also serves as a higher level roadmap for the features/project.

5. Confidence in Your Code

You’re free to build new features, without the worry of introducing new bugs. No more sleepless nights worrying about taking features live.

6. Tests Reduce the Cost of Change

It will be more expensive (money and time) to ensure and make sure new features don’t break existing ones without tests. Complex systems might suffer more as tracking down bugs is difficult, and applying fixes might have adverse effects without tests.

7. Tests Defend Against Other Programmers

Undocumented, or code that isn’t clearly commented, might cause a developer to “refactor” odd code, just to end adding more bugs, or breaking the system. Tests prevent this.

8. Testing Forces You to Slow Down and Think

When adding a new feature or refactoring an existing solution, testing forces you to think about what the code is supposed to accomplish. If you write tests first, your code will be clean and simple, and do exactly what it is expected to.

9. Tests tell you when to stop coding and constrains features

It’s easy to go overboard and fancy up your code. Tests allow you to see when you hit your target, so you can move on to the next feature, and not deliver something the client didn’t want.

Imperfect tests, run frequently, are much better than perfect tests that are never written at all” - Martin Fowler

So if testing is awesome, why isn’t it standard practice?

Unit testing has been compared to going to the gym:

Unit testing is a lot like going to the gym. You know it is good for you, all the arguments make sense, so you start working out. There’s an initial rush, which is great, but after a few days you start to wonder if it is worth the trouble. You’re taking an hour out of your day to change your clothes and run on a hamster wheel and you’re not sure you’re really gaining anything other than sore legs and arms.

Then, after maybe one or two weeks, just as the soreness is going away, a Big Deadline begins approaching. You need to spend every waking hour trying to get “useful” work done, so you cut out extraneous stuff, like going to the gym. You fall out of the habit, and by the time Big Deadline is over, you’re back to square one. If you manage to make it back to the gym at all, you feel just as sore as you were the first time you went.” - benzado

Different types of testing

Each language/framework tends to have a preferred set of tests.

Unit testing (Fastest)

Test small isolated “units” of code e.g. lines, branches and statements.

End-to-end (e2e) testing (slowest)

Full spectrum test from point Start to End

Other types of test:

  • Integration tests
  • Functional tests
  • Acceptance tests
  • Service tests

Test Driven Development (TDD)

Test-driven development (TDD) is a software development process that relies on the repetition of a very short development cycle:

  1. first the developer writes an (initially failing) automated test case that defines a desired improvement or new function
  2. then produces the minimum amount of code to pass that test
  3. and finally refactors the new code to acceptable standards.

Behaviour Driven Development (BDD)

  • Subset of TDD
  • Meaningful to non-developers
  • Build stories that satisfy app features
  • e.g. “App should highlight valid email field”

Sample test code

An example of an Angular.js test from the Agora project:


'use strict';

describe('Service: configService', function () {
  // load the service's module
  angular.module('configService.Mock', ['agora']).
    constant('TITLE', 'test').
    constant('DESC', 'test more').
    constant('API', 'http://example.com/');

  beforeEach(module('configService.Mock'));

  // instantiate service
  var service;

  // Initialize the controller and a mock scope
  beforeEach(inject(function (configService) {
    service = configService;
  }));

  it('Should return correct config details', function () {
    expect(service.title).toBe('test');
    expect(service.desc).toBe('test more');
    expect(service.api).toBe('http://example.com/');
  });
});

Sources

  • http://stackoverflow.com/questions/67299/is-unit-testing-worth-the-effort
  • http://geekswithblogs.net/jboyer/archive/2011/09/07/5-reasons-why-unit-testing-is-funndashand-important.aspx
  • http://www.onjava.com/pub/a/onjava/2003/04/02/javaxpckbk.html
  • http://www.yearofmoo.com/2013/01/full-spectrum-testing-with-angularjs-and-karma.html
Created: Thu, 13/02/2014 - 16:49