Live data from Hacker News

Write tests. Not too many. Mostly integration

blog.kentcdodds.com

241–250 of 338 posts

Re: Write tests. Not too many. Mostly integration

#241
post #149

So much people in this thread is talking about different domains and are not able to see that they need different rules. It is not the same creating a library that is going to be used to launch a multi-billion rocket to Mars than developing a mostly graphical mobile app where requirements are changing daily as you A/B test your way into better business value. The article has really good points and the reasons why the…

Ok, but at some point you have to decide what you’re actually going to do.

Re: Write tests. Not too many. Mostly integration

#242
post #74

Earlier quoted context omitted.

> If your app relies heavily on using a database, your app naturally integrates with a database then it makes no sense to test without it. You are intentionally avoiding testing in a way that will pick up bugs. Also, with Docker it's now actually feasible to automatically test against a real database at a reasonable speed. A Postgres container spins up in a couple of seconds, a SQL Server one in a little over four.

That has nothing to do with docker, really. I run postgres standalone on my laptop and it starts in < 1 second.

I guess they meant so your tests can start with a blank or reproducible state.

But you can of course achieve the same by running a script before your tests start. There are also some frameworks for doing this sort of thing too, such as Fixie for .NET

Re: Write tests. Not too many. Mostly integration

#243

Testing. My current theory for why there is so much confusion about testing is because developers are not often taught the difference between specification (theorems) and implementation (proofs) and why you want to separate the two. It seems like business and investors want us to write code, more of it, and faster. Value, value, value! So my question is: what is valuable? Do you value your customers' data? Do you val…

> Liveness having to do with maintaining invariants over the lifetime of a computation.

Nit: liveness is about reaching 'good' states over the lifetime of your computation. If your invariant is violated, even if it's a multistate invariant, it's still a safety error. Liveness would be something like "x is eventually true", or "the program always terminates."

It's not just specifications we need. We also need better tests. "Better" here doesn't mean "integration" or "acceptance", it means things like "fuzzing through contracts" or "comparing snapshots" or "rules-based state machines". Testing is vast and we're not very good at it.

Re: Write tests. Not too many. Mostly integration

#244
post #26
post #3

Good lord. Why integration tests? I think the biggest thing you can do to write more integration tests is to just stop mocking so much stuff. Okay. The biggest problem I see with people trying to write unit tests is that they don’t want to change how they write code. They just want tests for it. It’s like watching an OO person try their hardest to write OO code in a functional language. So they try to write E2E tests…

No true Scotsman. You might be speaking about those cases where people write large god classes, pervasively side-effectful code, zero API design, and a general lack of pure abstractions - then their tests would equally be bad. Tests are code, so one's ability to design programs would reflect on their tests and vice versa. But a reasonable programmer who cares enough about what they do can still end up with a brittle…

Yup, agree. Depending if you are working with a good static type system or with a dynamic language the value of unit tests can vary.

When working with dynamic languages I always end up writing a bunch of unit tests and a bunch of integration tests. I've experimented some with type hinting and static analysis in some dynamic languages but it's not the same as having the compiler make guarantees.

Re: Write tests. Not too many. Mostly integration

#245
post #3

Good lord. Why integration tests? I think the biggest thing you can do to write more integration tests is to just stop mocking so much stuff. Okay. The biggest problem I see with people trying to write unit tests is that they don’t want to change how they write code. They just want tests for it. It’s like watching an OO person try their hardest to write OO code in a functional language. So they try to write E2E tests…

>Unit tests run faster, are written faster, and not only can they be fixed faster, they can be deleted and rewritten if the requirements change.

Honest question: Are most of your unit test failures due to bugs or due to refactoring (e.g. changing APIs)?

Most people I know who do unit testing have mostly the latter (easily over 80% of the time). At that point one feels like they are merely babysitting unit tests.

If unit tests have such high false positives, how useful are they?

Note I'm not saying that it's not possible to write unit tests that are relatively immune from refactors. But it is more challenging and, in my experience, quite rare to find a project that writes them this way.

Re: Write tests. Not too many. Mostly integration

#246

Earlier quoted context omitted.

> as much as you can into static helper functions and most of the rest into dumb private stateless functions In our work we use C# and it is very hard, even next to impossible to make a static class pass a code review - given it's not for extension methods (which I hate... why not be explicit about the first parameter and stop acting as a part of the class ). They just tell us to use IoC and move to the next point. I…

Why hate extension methods? Do you really want to write Enumerable.ToList(Enumerable.Select(Enumerable.Where(someList, e => e.someBool), e => new {a = e.x, b = e.y)) and so on?

That would suck, on the other hand, the extension methods make people create huge chains continuations of which comes from who knows where.

Best solution would have been a pipe operator if you ask me.

Re: Write tests. Not too many. Mostly integration

#247
post #5

Behavior driven development (BDD) and test driven development (TDD) enable much faster coding when done well in my experience, and that includes full coverage fast unit tests, functional tests, benchmark tests, and integration tests. Unit tests are worth their weight in gold for quickly finding issues, both in our team's code and especially in cases of subtle changes among language releases, or unanticipated input ch…

For large code bases in dynamic languages I think the advantage grows larger over time. Even a modest amount of test coverage will allow you to build new features without breaking existing features.

It's a lot faster to catch bugs when the tests run in your local development environment or in the CI pipeline than to wait until Q/A (hopefully) catches them in end-to-end integration testing and sends it back to you for rework.

The other advantage I've noticed is that the tests can serve as an additional form of documentation. New team members can look through the tests to see how code is supposed to work from the examples there. For some web API projects I've even been able to generate the documentation from the test cases.

Re: Write tests. Not too many. Mostly integration

#248

Earlier quoted context omitted.

Not really. It makes you commit to an API upfront, this is the exact opposite of what exploratory programming should be (noncommittal, keep everything open).

No with TDD you don't need to go in with a structure in mind, the structures arise as you write more tests and get a proper understanding of what components you'll require. Red, green, refactor - each refactor brings you closer to the final design.

That's the mantra often quoted but it always makes me think of the famous Sudoku example from Ron Jeffries. Basically as a mantra it falls down if you don't understand the problem domain. It's popular because it works for the sort of simple plumbing that makes up a lot of programming work. This problem is particularly true for anything creative you're trying to express as the requirements are often extremely fuzzy and require a lot of iteration.

If you don't know how to solve a problem you actually need to do some research and possibly try a bunch of different approaches. Over encumbering yourself with specific production focused methodologies hurts. If you're doing something genuinely new this can be months of effort.

After the fact you should go back and rewrite the solution in a TDD manner if you think it benefits your specific context.

Re: Write tests. Not too many. Mostly integration

#249
I go the complete opposite way.

I've tried various testing strategies over 15~ different companies in all sorts of environments, and unit tests are the only thing that really work (IF you can convince the team to do it...and that's a big IF).

The article starts with a point I agree with: the lower in the pyramid, the cheaper the tests but the lower the confidence level they bring. That's true.

Where I disagree is how much the difference on confidence and cost are.

I can bang out 500 unit tests faster than I can do just a few E2E tests in most large apps. They require almost no trial and error, no real engineering (I feel strongly that abstraction in unit tests is bad), and all around are so easy to write, I don't mind if I have to toss out 150 of time when I make a significant refactor.

E2E tests are amazingly brittle and require a careful understanding of the whole system. They're impossibly expensive to write. They're the only thing that tells you that stuff works though. So you want at least a few of these.

Integration tests are just flat out awkward: you need understanding of a significant portion of code you did not write or touch, they often require complex fixtures (because your test will go through several code paths and might depend on a lot of arguments), they're slower (because a lot of code run), and while you don't throw them away when changing implementation details (unless they involve side effects), you still throw them away when refactoring or changing public interfaces. I've worked with a lot of people who were very vocal about these being so much better, then in the same breath complain that they spent all day writing integration tests.

There's an exception here which is acceptance tests for libraries, especially when doing a full rewrite: the tests that tell you public interfaces used outside of the current context work (as opposed to public interface of objects used in the implementation). Eg: if I was to test lodash or react, that's how I'd do it.

Unit tests to be are about a lot more than "is this change breaking my code". And if that's all you care about, you're missing a big part of the point.

If you have 3 units, A, B and C. A calls B which calls C. If you have a test for A in the context of B, a text for B in the context of C, and a test for C, and they all pass, you know that A + B + C will work. But when writing the tests, you only had to care about itty bitty tiny pieces of code, which made things super cheap.

Then you get other huge benefit: the quality of the entire code base is higher (a side effect of it having testable interfaces all across), the reasoning behind each piece of code is explicit (no one wrote a function that work and they 're not sure why, else the test would be very hard to write), you automatically have a document representing "intentions".

And yes, if you change a module, even if its not expose to your customers, the public interface of that module has tests and the tests will break. But they usually take nothing but a few minutes (often a few seconds) to write. They're cheap enough to be disposable.

And once you have 80%ish unit test coverage, you actually have a very high confidence level. I've gone through major refactoring of multi-million line of code apps with almost no bugs on pure unit tests. You't think the 20% of untested code would be a source of bug, but statistically, that's just not how it happens.

In term of person-hour to ROI, pure unit tests just straight up win out.

The reason software engineers fight back to hard against them is that they're brain dead and repetitive to write, and they can't resist overengineering. "This is such a simple test for such a simple piece of code, why should I test it?!". That's the point. All unit tests should be like this.

Re: Write tests. Not too many. Mostly integration

#250
post #224
post #134

Earlier quoted context omitted.

The bubble happens to be at the bottom of everything everyone runs. If we--or kernel folks for that matter--applied the advice of the article to our development practices, our system meltdown would be your system meltdown. Sure, you have requirements from management. So do architects and engineers for building bridges. Yet they still have a duty to build bridges that don't fall down.

Are you suggesting that the Linux kernel is unit tested? Last I checked, I couldn't find them. And discussions online say the same (e.g., https://news.ycombinator.com/item?id=9543336 and https://news.ycombinator.com/item?id=9544306 ). Kernel bugs tend to show up in userspace. Fortunately, integration-oriented projects have arisen more recently such as https://kernelci.org/ and https://github.com/os-autoinst/openQA/ A…

https://cs.chromium.org/chromium/src/v8/test/unittests/
Post reply on HN