Say I have a method A which calls a method B and does one additional thing. The B method behaves differently in 10 different cases and I have a broad unit test describing it. And now I want to test my method A. What is the best practice to do that? Should I run the same test with all 10 cases for method A to make sure that proper method is run? It sounds like an overkill. Or maybe I should test only one of that cases? But there's a risk that in future I'll write some method which will be quite similar to B and there will occure a bug which won't be detected by the test. Or maybe there are some ways of checking that my B method was fired just by registering its name? Maybe that's quite simple problem, but I'm new in unit testing and I haven't found any clear answer.
-
1Possible duplicate of [How should I test the functionality of a function that uses other functions in it?](https://softwareengineering.stackexchange.com/questions/225323/how-should-i-test-the-functionality-of-a-function-that-uses-other-functions-in-i) – gnat May 23 '18 at 10:45
2 Answers
You're question isn't completely clear to me, so I'm making the following assumptions:
- Method
A
andB
are both "public", - Method
B
has 10 execution paths through it and 10 test cases covering those paths, - Method
A
callsB
via at least one of its execution paths. - There are paths through
B
that are not used byA
.
Also, I'm going to have to ignore "But there's a risk that in future I'll write some method which will be quite similar to B and there will occur a bug which won't be detected by the test" as I don't see how it's related to either your question or testing A
and B
.
The first thing I'd say is do not try to mock B, unless you absolutely have to. This is a classic testing newbie mistake that many folk make. You only want to isolate A
from B
if the latter has side-effects or is slow. If you mock out B
, you'll simply be testing A
against the mock functionality, rather than B
's real functionality and you'll miss bugs as a result.
The next thing to ask yourself is, can you repurpose some of those B
test cases to have them test A
and B
together? So if you have four paths through B
that are used by A
, test those paths via testing A
. There's a huge caveat here though. Bear in mind that each of those tests will then tightly couple itself to existing functionality of A
and B
. If you later change A
to have that functionality itself for example, you could end up not testing that part of B
. Or changes might break tests just because the test is now brittle, not because you broke functionality, etc. As ever, there's a balance to be had between principle (test everything!) and pragmatism (I've got to ship this one day for there to be value in what I'm doing).

- 38,972
- 9
- 88
- 121
-
-
4@DanRayson, No, not the dreaded "expert" tag. :) Experts (think) they are masters of their domain; knowing all there is to know. After 35 years of software development, I still strive to be a beginner: there's just still so much to learn and so many good, new ideas coming through all the time. I'll accept "highly opinionated know-it-all", but never "expert" :) And I don't think you should delete your answer either. Let others decide on the relative worth of each. – David Arno May 23 '18 at 11:51
-
@DavidArno, Is it true that as soon as we add an additional dependency into our SUT (method B), we are no longer unit testing, but instead, we are integration testing? I usually create two test projects per dll. A unit testing project, in which I mock out ALL dependencies in the SUT, and an integration testing project, in which I test the SUT with all its dependencies. – Vin Shahrdar May 29 '18 at 16:01
I'm new in unit testing and I haven't found any clear answer.
In many cases, there isn't a clear answer: just different trade offs that you need to evaluate for your own circumstances.
The talk you need to watch is Integrated Tests are a Scam, by J.B. Rainsberger. See also his blog.
You might also want to review some wisdom from Kent Beck (2008)
I get paid for code that works, not for tests, so my philosophy is to test as little as possible to reach a given level of confidence
One of the motivations of unit tests is that they constrain your choice of implementations; the idea being that the tests give you a signal that your changes have produced an observable change in the behavior of your system.
So if you have a bunch of tests for B
, and assume that those cover A
as well, that's fine right up until the point that somebody decides to change the implementation of A
.
If A is-a
B; meaning that you are supposed to be able to replace a B
with an A
and still have a correct program, then a potentially useful trick is to write one suite of tests that gets invoked on both A and B.
void verifyThatItWorks(SystemUnderTest sut) {
// this is where the implementation of the test lives
// including the setup, activity, and verification
// aka arrange, act, assert
}
@Test
void testB () {
verifyThatItWorks(new B())
}
@Test
void testA () {
verifyThatItWorks(new A())
}
In some programming languages, there are conveniences that allow you to manage parallel copies of large test suites
abstract class AbstractSpecification {
SystemUnderTest sut
protected AbstractSpecification(SystemUnderTest sut) {
this.sut = sut;
}
@Test behavior1 () {...}
@Test behavior2 () {...}
// ...
}
class BSpecification extends AbstractSpecification {
BSpecification () { super (new B()); }
}
class ASpecification extends AbstractSpecification {
ASpecification () { super(new A()); }
}

- 32,131
- 2
- 42
- 79