In the context of unit testing, what is a "unit"?
We define 'unit' to be a single class.
As you rightly assert 'unit' is an ambiguous term and this leads to confusion when developers simply use the expression without adding detail. Where I work we have taken the time to define what we mean when we say 'unit test', 'acceptance test', etc. When someone new joins the team they learn the definitions that we have.
From a practical point of view there will likely always be differences of opinion about what a 'unit' is. I have found that what is important is simply that the term is used consistently within the context of a project.
Can be different things. A Class, a Module, a File, ... Choose your desired granularity of testing.
While the definition can vary, a "unit" is a stand-alone piece of code.
Usually, it's a single Class.
However, few classes exist in isolation. So, you often have to mock up the classes that collaborate with your class under test.
Therefore, a "unit" (also called a "fixture") is a single testable thing -- usually a class plus mock-ups for collaborators.
You can easily test a package of related classes using the unit test technology. We do this all the time. There are few or no mocks in these fixtures.
In fact, you can test whole stand-alone application programs as single "units". We do this, also. Providing a fixed set of inputs and outputs to be sure the overall application does things correctly.
I usually define it as a single code execution path through a single method. That comes from the rule of thumb that the number of unit tests required to test a method is equal to or greater than the method's cyclomatic complexity number.
A unit is any element that can be tested in isolation. Thus, one will almost always be testing methods in an OO environment, and some class behaviours where there is close coupling between methods of that class.
I would say a unit is a 'black box' which may be used within an application. It is something which has a known interface and delivers a well-defined result. This is something which has to work according to a design-spec and must be testable.
Having said that, I often use unit testing when building items within such 'black boxes' just as a development aid.
I would say that a unit in unit testing is a single piece of responsibility for a class.
Of course this opinion comes from the way we work:
In my team we use the term unit tests for tests where we test the responsibilities of a single class. We use mock objects to cover for all other objects so that the classes responsibilites are truly isolated and not affected if other objects would have errors in them.
We use the term integration tests for tests where we test how two or more classes are functioning together, so that we see that the actual funtionality is there.
Finally we help our customers to write acceptance tests, which operate on the application as a whole as to see what actually happens when a "user" is working with the application.
This is what makes me think it is a good description.
Were I work a 'unit' is a function. That is because we are not allowed to use any thing other than functional decomposition in our design (no OOP). I agree 100% with Will's answer. At least that is my answer within the paradigm of my work in embedded programming for engine and flight controls and various other systems.
In my experience the debate about "what is a unit" is a waste of time.
What matters far more is "how fast is the test?" Fast tests run at the rate of 100+/second. Slow tests run slow enough that you don't reflexively run them every time you pause to think.
If your tests are slow you won't run them as frequently, making the time between bug injection and bug detection longer.
If your tests are slow you probably aren't getting the design benefits of unit testing.
Want fast tests? Follow Michael Feather's rules of unit testing.
But if your tests are fast and they're helping you write your code, who cares what label they have?
My understanding (or rationale) is that units should follow a hierarchy of abstraction and scope similar to the hierarchical decomposition of your code.
A method is a small and often atomic (conceptually) operation at a low level of abstraction, so it should be tested
A class is a mid-level concept that offers services and states and should therefore be tested.
A whole module (especially if its components are hidden) is a high-level concept with a limited interface, so it should be tested, etc.
Since many bugs arise from the interactions between multiple methods and classes, I do not see how unit testing only individual methods can achieve coverage, until you already have methods that make use of every important combination, but that would indicate that you didn't test enough before writing client code.
That's not important. Of course it's normal you ask to get started on unit testing, but I repeat it, it's not important.
The unit is something along the lines of :
- the method invoked by the test. In OOP this method has to been invoked on an instance of a class (except static methods)
- a function in procedural languages.
But, the "unit", function or method, may also invoke another "unit" from the application, which is likewise exercised by the test. So the "unit" can span over several functions or even several classes.
"The test is more important than the unit" (testivus). A good test shall be :
- Automatic - execution and diagnostic
- Fast - you'll run them very often
- Atomic - a test shall test only one thing
- Isolated - tests shall not depend on each other
- Repeatable - result shall be deterministic