In a test, asserting if a simple method throws an exception under a certain circumstance, is such a test considered a unit or integration test when the exception object thrown is from the standard library of the programming language?
4 Answers
Doesn’t matter.
I can throw an exception from a standard library by trying to open a file that doesn’t exist or by dividing an int by zero.
What makes it a unit test only has to do with how you define your unit.
There are many definitions. One of the best I found here:
A test is not a unit test if:
- It talks to the database
- It communicates across the network
- It touches the file system
- It can't run at the same time as any of your other unit tests
- You have to do special things to your environment (such as editing config files) to run it.
artima.com - A Set of Unit Testing Rules by Michael Feathers
Under that the missing file is integration. The division is unit. And in neither is my code directly doing the throwing.
Now sure, some people consider two classes talking integration. Every class is a unit. If that’s you then, hell, guess what? An exception is another class.
I implore you, define your unit in a useful way that makes sense. Don’t just pick the laziest way to define it so you can avoid needing to think.
Because if you do it won’t mean anything when you say it’s a unit test.
-
1“Dividing an Int by zero” will often be either undetectable, or kill the running process, but not throw an exception. Commented Jul 18, 2023 at 7:38
-
If you're testing that your code throws an exception (for example, throw Exception("some text") if foo
, it's a unit test. If you're testing that the standard library throws an exception (for example, in case of a division by zero), it's still a unit test, but probably either pointless (it's testing what is hopefully already extremely-well tested third party code) or should be changed to test the relevant part of your code.
-
I would argue that the standard library is a framework, therefore granting it a sort of clearance from either needing to be tested or treated as some kind of component, since a component implies interchangeability.– FlaterCommented Jul 17, 2023 at 23:49
You're getting too granular with your definitions. Zoom out a bit.
The language's framework is part of the language, and is not considered a component in the sense of a unit test, nor a mock, nor one of the components being integrated. It is considered a universal truth and you do not write tests to confirm its behavior.
Laterally, I would argue that the issue here is that you should be throwing one of your own exceptions here. Throwing someone else's exception is a breach of encapsulation and tightly couples your implementation to your consumer.
However, I cannot exclude that your component is explicitly defined to throw a specific exception type that is intentionally premade as a matter of standardization (e.g. C#'s ArgumentException
), in which case it's not explicitly required to wrap it in a custom exception type.
Regardless, what you're testing is your component's public behavior. What you're not testing is (a) the language/framework itself, nor (b) the private implementation details of your component.
To be clear about (b), I mean that the test is not designed around your specific implementation. Of course, when running the test you'll be executing that implementation but this should not be obvious from the test's design.
If this exception could only be possibly thrown by this framework tool and not something you wrote yourself, then this exception should not be part of your component's public contract.
A unit test verifies that a method does what it is supposed to do. It doesn’t care how the method does it. Whether the method calls throw, or calls a standard library method that throws in some situations, or calls one of your own methods elsewhere in your application that throws, or catches an exception and throws its own exception as a result, it doesn’t matter. It is a unit test.
-
1I'm not a testing expert by any means, but couldn't everything be defined as a "unit" test when you apply this logic? If the exception that's thrown requires a lot more resources/components to be used before the function under test can reach that state, shouldn't it actually be consideren an integration test? Commented Jul 18, 2023 at 8:32