Live data from Hacker News

Stop mocking your system

blog.bitgloss.ro

101–110 of 178 posts

Re: Stop mocking your system

#101
we had a entire system fail because it was based on how the TDD test author (who left the company) felt the system should work.

basically, TDD sank us, because the code worked to make the test pass, versus the code working to support the business use cases.

sure, this wasn’t TDD problem, but was caused by a TDD zealot who didn’t bother to really do proper integration testing and work with stakeholders.

Re: Stop mocking your system

#102
post #73
post #51

True "unit" tests are: * faster to run * give you less confidence in the correctness of the system (per time spent writing them) * when they fail, give you more information about where the failure is The more integration-y/e2e-y a test is, the more it strays from this: slower to run, more confidence that the system is correct, less info about where the failures are. I think people have learned to undervalue the prope…

Don't forget a very important thing: unit test are hindering any refactoring. People will resist it because it means they have to rewrite their tests. And if you don't have enough e2e tests, you have nothing to check your refactoring efforts have not broken anything.

> Don't forget a very important thing: unit test are hindering any refactoring. People will resist it because it means they have to rewrite their tests.

Well, unit tests verify a contract. If a developer wants to change code but is incapable of respecting a contract (i.e., preserving old invariants or adding new ones that make sense) then he should not be messing with that code at all, shouldn't he?

In that sense alone, it's quite clear that unit tests pay off and add a lot of.value, namely in avoiding needless regressions from Rambo developers who want to change code without caring if it even works.

Re: Stop mocking your system

#103
post #19

Earlier quoted context omitted.

I'm confused as to where any mention of integration tests are? Integration tests can't use Mocks, as then they wouldn't be testing the integration. Unit tests can use Mocks, but as the article and GP and Mark Seemann[0] points out, that is always worse than writing your logic in a pure way, if you can. [0]: https://blog.ploeh.dk/2017/02/02/dependency-rejection/

Because you don’t gain as much as you think when you do this. Before your external external service touches your integration point and then runs some logic. You mock the external service to unit test the internal logic. Then you run integration tests to exercise the integration point. In the new world you have an external service talking to an integration point which then passes the data to your internal logic. You d…

> You mock the external service to unit test the internal logic

You only need the output produced by that external service or the the input expected by that service. For example, I can pass in a data structure or object representing the HTTP request to the method that I'm unit testing, but I don't need to mock a client to generate those requests to test that logic.

Re: Stop mocking your system

#104
post #34
post #28

Earlier quoted context omitted.

>The author seems to believe people either mock everything or don't mock anything. The author is saying that people frequently mock things that it would be more economic to just run because you've got the real thing right there. Building a model for it is an expensive waste that probably won't even match reality anyway and will demand constant maintenance to sync up with reality. If you're overtly concerned with the…

When I am developing a feature, I want to know very fast whether or not my code's logic is correct. It is not rare during the development cycle to run the same test dozens of times because I made a silly mistake (or a few), and obviously if the test takes 30 minutes to complete it completely wastes my day of work. Having a set of very fast running tests is absolutely necessary in my opinion. Once I have validated tha…

This sounds exactly right to me. You write mocks for the things that could take too much time to run frequently with the real code. (And I'm assuming you'd also write it for things that you don't want to make actual changes somewhere, such as a third-party API that you don't control.)

But if it could be run locally, quickly, you wouldn't bother mocking it.

If that's all correct, I think you and I would do the same things. All the people screaming "no mocks!" and "mock everything!" are scary, IMO.

Re: Stop mocking your system

#105
post #30

Earlier quoted context omitted.

>I think this is supposed to mean using dependency injection instead. I'm pretty sure he means "just use integration tests".

I think so too. Unfortunately, integration tests are too slow, so the practice doesn't scale if one is trying to TDD. Insinuating integration testing into every user story will lead to friction. Test run times will balloon, cycle times will get extended and resentment will grow for the test suite and the team's testing regime. If your test suites cannot complete quickly (seconds), then they cost more than they're wor…

Generally you shouldn’t really be using integration tests for TDD, but it’s totally possible to write your tests in a way where the dependency supplied is talking to a real system in one scenario and in another scenario is talking to a system with mocked responses - or any sort of level of depth in between.

However, I wouldn’t start out writing a system like this (aka TDD). From my experience, the best tested software looks like this as the end result and the design of the software itself has been forged in the same furnace.

Not sure if that completely makes sense, since some of these concepts are from functional programming and I never know what is totally foreign or totally obvious.

Re: Stop mocking your system

#106
> And guess what… you have to keep the mocks in sync with the real things

It is a valid problem but it's also possible to write mocks that are small and simple enough that this becomes trivial.

In my experience when testing a module necessitates a complex mesh of mocks and an intricate knowledge of inbound dependencies than this means that the problem are not the tests nor mocks but rather a problem tight coupling. The tests are simply telling us that in an unexpected way.

My rule of thumb is that if I can't mock it with a "every thing at default except what I want to test" than there's something wrong with the code, not the mocks.

And most integration tests can be eliminated by refactoring the code with proper contracts so that If A depends on B which depends on C then testing that A, B and C completes the chain of trust from A to C and doesn't necessitate an integration test from A to C.

> What you almost always want, when mocking, is really just different input data for your module

>What you almost always want, when mocking, is really just different input data for your module, data normally provided by a long stream of collaborators. Just build your program in such a way that you can send it this data, regardless of the runtime (unit test framework, test env or production env). Yes, it is possible and highly desirable and don’t be in denial right now.

Mocks are data in a nice, encapsulated and understandable form. I'd rather have a simple mock than "data provided by a long stream of collaborators". I can't recall how many hours I've lost by trying to reverse engineer huge pile of data and configuration files because the "tech lead" wanted a "life insurance" to make sure we broke nothing.

Re: Stop mocking your system

#107
post #73

Earlier quoted context omitted.

Don't forget a very important thing: unit test are hindering any refactoring. People will resist it because it means they have to rewrite their tests. And if you don't have enough e2e tests, you have nothing to check your refactoring efforts have not broken anything.

If a test is in my way, I delete it.

Then what is the point of it being there in the first place?

Re: Stop mocking your system

#108
> All of us have used mocks in our testing code, to substitute the real things. I know I’m definitely guilty of this. Why though? Why do we do it? Well, It’s usually because initialising those collaborators is not trivial (i.e. can’t be done with a one-liner).

I practically never mock something because I’m concerned that creating the real instance is more than a single line of code or non-trivial.

I don’t want my code making network requests if the actual instance is some kind of network/service client. As a matter of fact, I don’t want network requests in my unit tests. At that point, they’re not unit tests, and they could fail because the request failed or the system on the other end had issues - unrelated to what I’m actually trying to unit test.

I think the author fundamentally has a different idea of unit tests. I write unit tests and mock some dependency because I want to test some code in isolation where the “mock” is some interface with some possible inputs, outputs, or it fails perhaps by throwing an exception. And I can set up this behavior and validate my code gives me the expected outputs or makes some function call on a dependency.

The blog author seems to be conflating unit tests with integration tests, and I’m even wondering what’s the point - if I take them as objectively onto something, perhaps we should throwaway our tests and just test in production.

Re: Stop mocking your system

#109
post #51

True "unit" tests are: * faster to run * give you less confidence in the correctness of the system (per time spent writing them) * when they fail, give you more information about where the failure is The more integration-y/e2e-y a test is, the more it strays from this: slower to run, more confidence that the system is correct, less info about where the failures are. I think people have learned to undervalue the prope…

I think that a well covered codebase should include mostly unit tests, plenty of integration tests, and few E2E tests, i.e. model the test pyramid[1].

Mocking in unit tests is generally acceptable to avoid also testing other systems. E.g. if the function does OS or network calls it's a good idea to mock that and keep the test isolated. But you should also have integration tests for the feature which do make external calls without mocking (or mocking at a higher level), as well as E2E tests that test the system as a whole. This way you can generally quickly pinpoint where something breaks, which may or may not break higher level tests.

[1]: https://martinfowler.com/bliki/TestPyramid.html

Re: Stop mocking your system

#110

Why stop there? Why not delete your test methods too and just test in production? Mocks are just test code, same as your test functions. And they’re necessary fur unit tests. If the thing you’re testing talks to another component without a mock, it’s now an integration test instead of a unit test. Unit tests test the API surface of a component. They’re useful for ensuring a component adhere to its documented API cont…

> Why not delete your test methods too and just test in production? This, but unironically. Depending on your use case, any local tests, whether mocked or using a swarm of local containers attempting to represent production may be a far stretch from production reality. Put everything behind feature flags and test your contracts, then release to production regularly and test against live data and live services.

[deleted]
Post reply on HN