I have found multiple ways of looking at this:

  1. behaviour vs methods
  2. behaviour vs state
  3. behaviour vs implementation

(1) Unit-Test Behaviour, Not Methods

focus on the features that the object under test should provide,
We need to know how to use the class to achieve a goal, not how to exercise all the paths through its code.
Describing Behavior, Not API Features
We need to know how to use the class to achieve a goal, not how to exercise all the paths through its code.

(src: Book: Growing Object Oriented Software, Guided By Tests - Steve Freeman & Nat Pryce)

So behaviour here is the protocol, instead of the interface (Model: interface vs protocol)


(2) Test behaviour instead of state Another way of looking at it, is say ’test behaviour’ means

  • test the behaviour like a user would use it
  • or
  • test the system as it would be used

instead of:

@Test cannot_create_duplicate_users() {
// arrange
...
var user = new User("a name")
userRepository.add(user)

// act
var secondUser = createUser("a name")

// assert
expect(secondUser).toBeNull()
expect(userRepository.users.filter(name ~= "a name")).toBe(user)
}

do this:

@Test cannot_create_duplicate_users() {
// arrange
...

// act
createUser("a name")
createUser("a name")

// assert
expect(DuplicateUsernameNotAllowed)
}

The first ’tests the implementation' The second ’tests the behaviour'

With the second, you test the behaviour of the system. ‘registering a user with the same name twice is not allowed’

With the first, you test ‘if there is already a user with that name, you cannot create another user with that same name’


(3) Test behaviour instead of implementation

I have heard this phrase often. I have used it occasionally. But right now, it’s still pretty vague to me.