A unit should be a discrete element of your code that exhibits a behaviour that is important to the consumer. Often we mean the 'logic' of the application - something internal. But it could be a library API. The unit has behaviour; that behaviour is its surface.
What we don't want to do is test the internals of the unit; if a function is not exposed by the library, we should not test it unless we have a really, really good reason. Why?
Because tightly coupled tests create fragility. We rely on the unit tests to tell us that the behaviour of the code has not changed. If we're testing a layer below the level of behaviour that we care about - say the internals of our library - then we cannot refactor the code easily. Tests will break whenever we refactor the internals of the library; we will find it hard to say what behaviour we care about. We will feel like the tests are trapping us rather than liberating us.
I favour TDD, so I see tests as being a good test of the 'feel' of an API - if it's hard/horrible to call in the tests, then it's probably hard/horrible for real people.
M'learned colleague and friend @quii
gave a rather good talk on all of this:
tightly coupled tests create fragility. We rely on the unit tests to tell us that the behaviour of the code has not changed. If we're testing a layer below the level of behaviour that we care about - say the internals of our library - then we cannot refactor the code easily.
This succinctly summarizes what I've been struggling with, but I think the problem was I had the whole concept a little wrong. I was conflating "a discrete element" with "a function". This makes a lot of sense, thank you! I'll definitely check out the talk.
You're welcome. I don't think I express it very well - haven't quite found the right metaphor yet. It's something to do with shapes and how they're constructed. You're a clever chap - I'm sure you'll think of something.
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
What's a unit test? First answer: what's a unit?
A unit should be a discrete element of your code that exhibits a behaviour that is important to the consumer. Often we mean the 'logic' of the application - something internal. But it could be a library API. The unit has behaviour; that behaviour is its surface.
What we don't want to do is test the internals of the unit; if a function is not exposed by the library, we should not test it unless we have a really, really good reason. Why?
Because tightly coupled tests create fragility. We rely on the unit tests to tell us that the behaviour of the code has not changed. If we're testing a layer below the level of behaviour that we care about - say the internals of our library - then we cannot refactor the code easily. Tests will break whenever we refactor the internals of the library; we will find it hard to say what behaviour we care about. We will feel like the tests are trapping us rather than liberating us.
I favour TDD, so I see tests as being a good test of the 'feel' of an API - if it's hard/horrible to call in the tests, then it's probably hard/horrible for real people.
M'learned colleague and friend @quii gave a rather good talk on all of this:
youtube.com/watch?v=Kwtit8ZEK7U
As to coverage... it's a weak metric. Focus more on what a wise man once told Kent Beck:
Ah, this is quite helpful.
This succinctly summarizes what I've been struggling with, but I think the problem was I had the whole concept a little wrong. I was conflating "a discrete element" with "a function". This makes a lot of sense, thank you! I'll definitely check out the talk.
You're welcome. I don't think I express it very well - haven't quite found the right metaphor yet. It's something to do with shapes and how they're constructed. You're a clever chap - I'm sure you'll think of something.