2014 m. rugpjūčio 30 d., šeštadienis

Does mocking breaks encapsulation ?

Recently I had a discussion regarding unit testing and specifically about how mocking dependencies violates encapsulation. In other words i've been told that your tests should not fail if implementation of unit changes. You just test if given input results to expected output and what dependencies are used there and how, should not be included in your unit tests.

I do not agree with this. I believe unit tests should explain how unit will behave in certain conditions. These conditions can be created only by mocking dependencies. Your tests are like documentation which describes the logic of the unit and what were requirements at the time it was created. Now if your unit implementation will change and dependencies will be used differently or different dependencies will be used, but output of the unit will still be the same, you will have your unit tests that describes dependencies usage failing and only test which asserts output will still be passing. Is this ok ? Does this breaks encapsulation ? Should you be fixing your tests when implementation changes ? I'd say it does not break it and it is ok to change unit test along with refactored unit.

As I understand it, encapsulation allows you to hide the internals of the object and prevent code that is using that object to set it in some invalid or inconsistent state. Over exposed public methods we control access to our object and in this way we protect it from outside world. But does this means that unit tests should not know HOW that public method is working ? What are possible execution paths ? What is the logic of it ?

For me, unit test is a piece of code which is interested in internals of method and by writing tests we make sure that logic inside that method works as we expect. Unit test code is not the same as production code which uses that public method. Production code does depend only on the provided contract, but it does not care about internals and implementation. Besides with unit test we are not changing how our unit is working, all we do is just we change how dependencies behave and we do assert how and with what data those are being called.

Of course if you do not use inversion of control and your dependencies are created in private methods then you will be using reflection to mock these and that is changing internals of your unit. But I would still go for it and would mock it, because I want to be sure that my method works as expected in given conditions. And afterwords I would just refactor it so that dependencies could be injected.

My conclusion on this would be that mocking dependencies to test possible execution paths and tie up your tests to implementation details is ok and no encapsulation is violated here (with exception mentioned above). Because changing implementation is like changing documentation of your method and that should be mirrored on your unit tests.
Rašyti komentarą