单元测试

Why do unit-test

The objective in unit testing is to isolate a unit and validate its correctness.

a unit test should usually not go outside of its own class boundary, and especially should not cross such process/network boundaries because this can introduce unacceptable performance problems to the unit test-suite

unit testing is traditionally a motivator for programmers to create decoupled and cohesive code bodies. This practice promotes healthy habits in software development.

The process of writing a thorough set of tests forces the author to think through inputs, outputs, and error conditions, and thus more crisply define the unit’s desired behavior.

unit testing can force developers to structure functions and objects in better ways

Unit testing allows the programmer to refactor code or upgrade system libraries at a later date, and make sure the module still works correctly

Unit testing provides a sort of living documentation of the system.

unit testing takes time and its investment may not be worth the effort.

code for a unit test is likely to be at least as buggy as the code it is testing.

test-driven development (TDD)

TDD is not about testing.It is the process of approaching your design and forcing you to think about the desired outcome and API before you code.

behaviour-driven development(BDD)

a natural extension of TDD testing in general

should be written in order of business value

Acceptance tests should be written using the standard agile framework of a user story:

As a [role] I want [feature] so that [benefit]

Acceptance criteria should be written in terms of scenarios and implemented as classes:

Given [initial context], when [event occurs], then [ensure some outcomes]

Setup & Teardown

  • Repeating
  • One-time
  • Scoping/Story

Test Double

seperation

Method Stub

Stubs are used commonly as placeholders for implementation of a known interface, where the interface is finalized/known but the implementation is not yet known/finalized.

Fake Object

lightweight implementation, such as a in memory database

Test Spy

partial mocking, wrapper of a object, recomended for testing legacy code

Mock Object

very similar to Stub but interaction-based rather than state-based

it may be useful to use a mock object in its place:

  • the object supplies non-deterministic results (e.g. the current time or the current temperature);
  • it has states that are difficult to create or reproduce (e.g. a network error);
  • it is slow (e.g. a complete database, which would have to be initialized before the test);
  • it does not yet exist or may change behavior;
  • it would have to include information and methods exclusively for testing purposes (and not for its actual task).

Test coverage

100% test coverage is impossible and meaningless.

  • Function coverage – has each function (or subroutine) in the program been called?
  • Statement coverage – has each statement in the program been executed?
  • Edge coverage – has every edge in the Control flow graph been executed?
  • Branch coverage – has each branch (also called DD-path) of each control structure (such as in if and case statements) been executed? For example, given an if statement, have both the true and false branches been executed? This is a subset of edge coverage.
  • Condition coverage (or predicate coverage) – has each Boolean sub-expression evaluated both to true and false?

Good tests

  • run fast
  • doesn’t break often(reliable, repeatable)
  • well organized, readable, easy to understand

参考资料