-
Notifications
You must be signed in to change notification settings - Fork 59
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Highlight clearly why mocking is problematic #15
Comments
Yeah, I also have experienced using mocks for almost everything, especially when using phpspec 🙈. Did you see this section: https://github.com/sarven/unit-testing-tips#always-prefer-own-test-double-classes-than-those-provided-by-a-framework? I have an ambitious plan for this year to extend this guide and add an explanation for things like resistance to refactoring which may be not clear to everyone. However, it's not an easy task to explain a lot of things and keep this guide concise. |
Yes creating own test doubles is indeed a nicer way. I personally think mocks are not useful for testing anything valuable, they provide a false sense of security and almost never catch any real bugs. Most guides just repeat the same lingo about mocks vs stubs vs fakes, I think all of that is less important in output based testing. Some things which I find most guides don't cover:
|
I will try to cover these topics in the future, now just quick explanations:
|
I think that worth noting is also an aspect related to legacy app architecture, where we'd like to create a test before we change something. It would be really laborious to write test only with basic tools without mocking ability. Interesting take about the topic https://www.youtube.com/watch?v=uVHGt2qbjXI |
Thanks for the video, what i get from the video is that mocking is useful for fleshing out modular designs when doing TDD. One objects interaction with other objects is tested via mocks. I can understand it helping in the design process but I don't find it a good argument to keep such tests after the design process is over. Why should I commit and run tests tests which are just useful for design? Output based tests actually verify the design gives the right results which is important to test continuously. This is also why i don't understand how legacy apps can benefit from mocking, they are already not modular, and their design is set in stone. The only thing we care about is whether refactoring such code doesn't break anything. This is a great case for writing broad integration tests not unit tests with mocks. |
I really wish guides would separate out TDD and testing in general, majority of the projects don't use TDD, but would still like to verify their code works. Highly complicated objects are found across business code and still need to be tested even if we agree their design is bad.
Most bugs i face are edge cases, they don't happen always but only when the system is under a particular state. To get the system under the right state requires creating multiple objects with fake data and calling multiple methods in sequence to trigger the bug. Unless the object has been tested before it is usually a lot of work to set up. But it is necessary work which must be learned.
Yes I have come across mutation testing, it is certainly useful to give us an idea of how much we can rely on our tests to detect broken code. |
@aszenz Totally I agree with that. Writing unit tests with mocking for legacy code gives us no confidence when we want to refactor something. So I usually prefer writing an integration test when I have legacy code and I have to do some refactoring. I will try to cover this topic during the next iteration of developing this guide. It's getting bigger, testing seems to be a broad topic so it would be great to prepare a comprehensive ebook with all this knowledge. |
I agree with both of you, although as usual, it all depends. Sometimes legacy !== legacy. Mocking is required when the decomposition strategy has failed. For instance, I would mock some side effects made by I/O in a particular scenario rather than re-create everything from scratch or build a heavy integration test. I have worked with an app with the enormous cost of bootstrapping the container and test environment. |
We should encourage everyone to use TDD, it's an important technique to achieve better solutions. I think that tests and TDD are inherent topics.
There are practices that can help with that:
In legacy systems with bad architecture, no modularity, and so on, certainly creating good tests will be hard. But I think that it's worth investing some time and trying to work out a habit of always securing our change with broad integration tests and then we can change the logic under the hood more safely. I highly recommend this presentation: https://www.youtube.com/watch?v=2vEoL3Irgiw Mutation testing is very helpful to verify our unit tests. Using mutations for slower integration tests isn't viable. |
Yeah, of course, legacy systems are very different. However, I think that broad integration tests are usually the best for legacy systems with a bad design because we still have the possibility to change the logic underneath. It's often better to just allocate more resources, create the environment to execute tests in parallel, and so on, and just have the possibility to refactor that code. |
I often see developers using mocks for entities to simplify their creation for testing.
While this is easy enough it creates a lot of coupling to the implementation details.
I would like to see a clear warning that mocks shouldn't be used especially for data classes like entities which have no side effects
The text was updated successfully, but these errors were encountered: