suites-dev/suites

Sociable unit testing as first-class citizen?

soryy708 opened this issue · 1 comments

Is there an existing issue for this?

  • I have searched the existing issues

Is your feature request related to a problem? Please describe it

Automock as it is right now is great for solitary unit tests, but I often have a problem. When I refactor production code, I sometimes want to extract a new class to structure things better. However, because Automock assumes that a unit is only a single class, it makes it hard to change the existing unit tests to correctly use the new class. The conceptual unit didn't change, it's only a structural refactor, so it shouldn't be mocked.

It's inconvenient to work-around it right now, with:

const u1 = TestBed.create(Service1).compile();
const dep = u1.unitRef.get(Service3);
const u2 = TestBed.create(Service2).mock(Service1).using(u1.unit).mock(Service3).using(dep).compile();

Describe the solution you'd like

I'd like to be able to conveniently define which classes should not be mocked, because they're part of the unit under test.
Maybe something like:

TestBed.create([Service1, Service2]).compile();

What is the motivation / use case for changing the behavior?

mockists insist upon solitary unit tests, while classicists prefer sociable tests.

https://martinfowler.com/bliki/UnitTest.html

It would be great to support classicist strategies.


[...] tests [...] coupled to things that they should not be coupled to. In the case of his micro-tests, he was using too many mocks, and deeply coupling his tests to the implementation of the production code. That, of course, leads to fragile tests.

https://blog.cleancoder.com/uncle-bob/2017/05/05/TestDefinitions.html

I think coupling the tests to the classes structure too tightly is undesireable because it can lead to fragile tests.

http://xunitpatterns.com/Fragile%20Test.html

http://blog.cleancoder.com/uncle-bob/2014/12/17/TheCyclesOfTDD.html

As the tests get more specific, the code gets more generic.
As a test suite grows, it becomes ever more specific. i.e. it becomes an ever more detailed specification of behavior. Good software developers meet this increase in specification by increasing the generality of their code. To say this differently: Programmers make specific cases work by writing code that makes the general case work.
As a rule, the production code is getting more and more general if you can think of tests that you have not written; but that the production code will pass anyway. If the changes you make to the production code, pursuant to a test, make that test pass, but would not make other unwritten tests pass, then you are likely making the production code too specific.

We'll often start with production code and test code that is structured similarly.
In the simplest case, it's often true that the unit is a single class.
But as the production code is generalized, we'll want to refactor it, perhaps separating it to multiple classes.
So our previous tests, which implicitly mock all classes, will erroneously mock part of our unit as we extract classes. We'll need to somehow specify that these classes are to not be mocked.

Therefore we'll often want to take a pre-existing test suite written in solitary style automock, and convert it to sociable.