DEV Community

Discussion on: I need to stop saying "Unit Tests"

Collapse
matthewbdaly profile image
Matthew Daly • Edited on

A unit test is normally defined as something that tests a single "unit", or component of code. A unit can be a class or function, but any dependencies must be replaced with mocks for it to be a true unit test. For instance, a true unit test should never write to the database.

An integration test is one that tests two or more components together. It can still mock out dependencies if appropriate, but this should be rare. An integration test can be as high level as creating a dummy request object and passing it through the main application class, or as low level as just checking two classes work together as expected.

Finally, acceptance tests test the application from an end-user's point of view. As such they do things users might - log in, upload pictures etc, and they often either drive a real browser using something like Selenium, or use some high level interface to describe their I reactions. Even for these, it's often appropriate to mock out external dependencies- if you don't, you may get falsely broken tests due to a third party service going down, or find the API accidentally taking action you don't want, such as sending an email to customers.

Collapse
jamietwells profile image
jamietwells Author

A unit test is normally defined as something that tests a single "unit", or component of code. A unit can be a class or function, but any dependencies must be replaced with mocks for it to be a true unit test

And I think this is what confuses people. They see things like single unit and think single class. There's a reason they're not called class tests. Sometimes a single unit is more than just one class. That's how we end up with these rules where people are mocking out "calculator" classes instead of having them be static classes and covered by whatever test.

I think what I'm really wanting is for us to concentrate more on the ideas and concepts rather than dictionary definitions. That's probably why I'm after a new name for the tests I'm trying to describe. The more I think about it, the more I realise Spec Test is probably the closest name I can come up with to describe how I think about testing. Maybe I'll use that from now on.

What sort of tests do you value? What do you call them?

Collapse
matthewbdaly profile image
Matthew Daly

What sort of tests do you value? What do you call them?

I'm inclined to agree with the Testing Pyramid, which is used by Google, among others. I tend to get the most value out of having every class or function having most, if not all, paths tested with unit tests, then integration tests for things like a route (so, for instance, there will be an integration test for submitting a particular fotm), then maybe a few high level acceptance tests.

Because you control all the input to a class in a unit test, you can test situations that are difficult to simulate in integrated or acceptance tests, or test against a wide range of inputs that wouldn't be practical either higher level tests. For instance, if a class relies on a third party service, you can mock that service and have it throw an exception. Unit tests are also fast.

However, you can't rely solely on unit tests, as just because two classes work in isolation, that doesn't mean they interact correctly.

The more I think about it, the more I realise Spec Test is probably the closest name I can come up with to describe how I think about testing. Maybe I'll use that from now on.

Have you looked at some of the SpecBDD tools around? I found PHPSpec to be a revelation in terms of testing because it makes it more natural to test a class from the outside in. It mocks out dependencies by default and let's you concentrate on designing your classes by specifying what they should do, rather than focusing on implementation.