Over the years it’s becoming clear to me what’s an integration test and what’s a unit-test.
I understand some people more or less settle on their definitions but to be brief I consider testing one class, that does one thing, a unit – if it’s tests are deterministic, rapid to cook-up and don’t touch anything crossing it’s own process instead just testing business logic of that unit in-memory – it’s a “done” deal; I call that unit-testing.
But this class I’m cooking up messes with events, it emits and receives them.
A unit test I’m setting up deals with a scenario where 2 instances of the same class are running side-by-side; making sure each instance is only receiving the events it’s meant to receive.
By my own definition I’m unit-testing. On the other hand, this feels like I’m doing integration-testing, integrating my unit, with it’s itself.
Am I still unit-testing and if not, why?
The reason I’m asking is that I run my test-suites so many times per-day, introducing brittleness or slow tests tends to snowball and I’d like to avoid this pitfall.
3
Already established in another answer, the “unit” in unit test does not exclusively refer to a single class. Sometimes a handful of classes work together as a unit, at which point they can be tested in unison.
More importantly, however:
A unit test I’m setting up deals with a scenario where 2 instances of the same class (
Foo
) are running side-by-side; making sure each instance is only receiving the events it’s meant to receive.
That’s not a test of Foo
, that’s a test of the load balancer of Foo
, who for all intents and purposes is an external consumer of a Foo
instance (instances, in this case).
Edit: I’m calling it a load balancer for lack of a better name. Load balancers imply that it equally distributes events to instances. There might be a different reason for deciding which instance to assign an event to. That distinction is irrelevant for this answer, so I’m just going to refer to it as a load balancer and leave it at that.
Such a test does not require a real instance of Foo
. It can be swapped out with a mock that records what events it’s being given.
The proof is in the pudding: Foo
does not control which events it receives. Therefore, a test that focuses on the reception of events is not testing a responsibility of Foo
, it’s testing the responsibility of whoever is giving the events to the Foo
instance.
Am I still unit-testing and if not, why?
For a different reason than you’re arguing, you are definitely unit testing this. Having multiple Foo
instances is a red herring, because they can be mocked for the purpose of this test and they are actually not the unit under test in the first place.
The unit under test here is the load balancer, and therefore yes this is a unit test.
As an aside, don’t get too caught up with the nomenclature between unit and integration tests. It’s important to understand these concepts and that they each have different benefits and drawbacks. It’s less important to be able to label each test accurately and definitively, especially when considering intra-application integration tests vs unit tests.
8
The “unit” in “unit testing” isn’t necessarily a class. As Wikipedia correctly states:
Unit is defined as a single behaviour exhibited by the system under test (SUT), usually corresponding to a requirement. While it may imply it’s a […] a method or a class (in object-oriented programming) it doesn’t mean functions/methods, modules or classes always correspond to units. From the system-requirements perspective only the perimeter of the system is relevant, thus only entry points to externally-visible system behaviours define units.
In your specific case, it sounds like you are not testing just two instances of your class, but also something like an event gateway and that it is correctly connected to the instances. That sounds a lot like an integration test for me. On the other hand: is it possible to test the event handling of one instance of your class in isolation? That would be IMHO a unit test.
Also ask yourself: does it really matter how you call the test? If not, don’t overthink this. In practice, the borders between unit testing and integration testing are not “mathematically” strict, and it is to some degree dependend from the test author what they call a unit and what not.
See also:
- Unit testing vs Integration Testing
1
The outer limit for a unit test is IO. No DB, no file system, no networking. So it depends on where these events are going. If you’re sending them to some event server this isn’t a unit test. If you’re keeping them in the local memory space where they move around blazingly fast (either by design or by mocking) then calling this a unit test is fine.
Also, two objects being run side by side can absolutely be considered one unit. It’s not called object testing. It’s called unit testing.
6