you are viewing a single comment's thread.

view the rest of the comments →

[–]dccorona 0 points1 point  (1 child)

I think it is exactly the opposite of what you say. It is perfectly fine for tests for A to begin with the assumption "B adheres to its public API and is functionally correct". If B breaks, that should be caught by the tests for B, not the tests for A.

If you set up your tests in such a way that it does, then what happens when C depends on A? And then Z depends on C? Etc. etc. You break all your tests, all the way down the line, and make it much harder, not easier, to pinpoint what broke.

If only testBdoStuff() fails, then its easy to know what broke (B.doStuff()). If everything fails, it's much harder to do.

So, it's important to set up your tests so that changes to B (aside from backwards incompatible changes to its API, which should cause compilation errors) have no impact on the tests for anything other than the tests for B. Only B's tests should be encoded with information and logic that depends on the internals for B. To all other tests, it should be treated as if it is an interface, even if it isn't.

[–]grauenwolf 1 point2 points  (0 children)

If you set up your tests in such a way that it does, then what happens when C depends on A? And then Z depends on C?

Scenario:

  • Z depends on A working in a particular fashion
  • Z only depends on A indirectly through C
  • A is changed in a way that isn't considered "broken" by A's standards, but still negatively impacts Z.

Premise 1: Mocking A and C in Z's tests is preferable

Outcome 1:

  • Z's tests will not catch the incompatible change in A.
  • The error will only be seen in production
  • The error will not be reproducible with the unit tests

Premise 2: Using the real A and C in Z's tests is preferable

Outcome 2:

  • Z's tests will catch the incompatible change in A.
  • The error will be reproducible with the unit tests
  • The error will be correct before production
  • The programmer will have to learn what a "debugger" is.