News for hackers. Stuff that matters.
Re:Is TDD Dead? (2014) by crazygringo on Wednesday August 26, 2020 @10:14AM (#24282646)
> you should delete tests for everything that isn't a required external behavior

Wait, I'm terribly confused here.

Aren't a huge part of tests to prevent regression?

In attempting to fix a bug, that could cause another "internal" test to fail and expose a flaw in your bugfix that you wouldn't have caught otherwise. And it's not uncommon for your flawed bugfix to not cause an "external" test to fail, because it's related to the codepath there was never a good enough external test for in the first place -- hence why the bug existed.

I can't imagine why you would ever delete tests prematurely. I mean, running internal tests is cheap. I see zero benefit for real cost.

And not only that, when devs don't document the internal operation of a module sufficiently, keeping the tests around serves as at least a kind of minimal reference of how things work internally, to help with a future dev trying to figure it out.

If you're refactoring an implementation, then obviously at that point you'll delete the tests that no longer apply, and replace them with new ones to test your refactored code. But why would you delete tests prematurely? What's the benefit?

Re:Is TDD Dead? (2014) by alexbanks on Wednesday August 26, 2020 @03:24PM (#24286239)
> In attempting to fix a bug, that could cause another "internal" test to fail and expose a flaw in your bugfix that you wouldn't have caught otherwise.

If an external test passes and an internal test fails, the external test isn't really adding any value, is it? And if the root of your issue is "What if test A doesn't test the right things", doesn't the whole conversation fall apart (because then you have to assume that about every test)?

IME this is a common path most shops take. "We have to write tests in case our other tests don't work." Which is a pretty bloaty and wildly inefficient strategy to "Our tests sometimes don't catch bugs." Write good tests, manage and update them often. Don't write more tests to accommodate other tests being written poorly.

> I mean, running internal tests is cheap.

Depends on your definition of cheap, I guess.

My last job was a gigantic rails app. Over a decade old. There were so many tests that running the entire suite took ~3 hours. That long of a gap between "Pushed code" and "See if it builds" creates a tremendous amount of problems. Context switching is cost. Starting and unstarting work is cost.

I'm much more of the "Just Enough Testing" mindset. Test things that are mission critical and complex enough to warrant tests. Go big on system tests, go small on unit tests. If you can, have a different eng write tests than the eng that wrote the functionality. Throw away tests frequently.

Re:Is TDD Dead? (2014) by crazygringo on Wednesday August 26, 2020 @03:53PM (#24286539)
I understand what you're saying, but in my experience that's not very robust.

I've often found that an internal function might have a parameter that goes unused in any of the external tests, simply because it's too difficult to devise external tests that will cover every possible internal state or code path or race condition.

So the internal tests are used to ensure complete code coverage, while external tests are used to ensure all "main use cases" or "representative usage" work, and known frequent edge cases.

That doesn't mean the external tests aren't adding value -- they are. But sometimes it's just too difficult to set up an external test to guarantee that a deep-down race condition gets triggered in a certain way, but you can test that explicitly internally.

It's not that anyone is writing tests poorly, it's just that it simply isn't practically feasible to design external tests that cover every possible edge case of internal functionality, while internal tests can capture much of that.

And if your test suite takes 3 hours to run, there are many types of organizational solutions for that... but this is the first I've everd heard of "write less tests" being one of them.

Re:Is TDD Dead? (2014) by _t0du on Wednesday August 26, 2020 @04:50PM (#24287128)
> I've often found that an internal function might have a parameter that goes unused in any of the external tests,

It seems that you're still thinking about "code". What if you thought about "functionality"? If an external test doesn't test internal functionality, what is it testing?

> But sometimes it's just too difficult to set up an external test to guarantee that a deep-down race condition gets triggered in a certain way, but you can test that explicitly internally.

I would argue that if you're choosing an orders of magnitude worse testing strategy because it's easier, your intent is not to actually test the validity of your system.

> while internal tests can capture much of that.

We can agree to disagree.

> And if your test suite takes 3 hours to run, there are many types of organizational solutions for that... but this is the first I've everd heard of "write less tests" being one of them.

I was speaking about a real scenario that features a lot of the topics that you're describing. My point was not that it was good, my point was that testing dogmatism is very real and has very real costs. To describe writing/running lots of (usually unnecessary) tests as "cheap" is a big red flag.

Re:Is TDD Dead? (2014) by jharger on Wednesday August 26, 2020 @10:04PM (#24289469)
Not the poster you replied to, but I've been thinking of it lately in a different way. Functional tests show that a system works, but if a functional test fails, the unit test might show where/why.

Yes, you'll usually get a stack trace when a test fails, but you might still spend a lot of time tracing exactly where the logical problem actually was. If you have unit tests as well, you can see that unit X failed, which is part of function A. Therefore you can fix the problem quicker, at least for some set of cases.

Re:Is TDD Dead? (2014) by jacobr1 on Thursday August 27, 2020 @06:56PM (#24299595)
It is a combinatorial explosion problem.

Internal code A has 5 states, piece B has 8 states.

Testing them individually requires 13 tests.

Testing them from out the outside, requires 5x8=40 tests.

Now, if you think of it that way, maybe you _do_ want to test the combinations because that might be source of bugs. And if you do it well, you don't actually need to write 40 tests, you have have some mechanism to loop through them.

But the basic argument is that the complexity of the 40 test-cases is actually _more_ than the 13 needed testing the internal parts as units.

FWIW, my own philosophy is to write as much pure-functional, side-effect free code that doesn't care about your business logic as possible, and have good coverage for those units. Then compose them into systems that do deal with the messy internal state and business-logic if statments that tend to clutter real systems, and ensure you have enough testing to cover all branching statements, but do so from an external to the system perspective.

Re:Is TDD Dead? (2014) by btschaegg on Thursday August 27, 2020 @01:25AM (#24290393)
I've got the impression that you are both talking slightly past each other.

At least my impression is that these "internal tests" you talk about are valid unit tests -- but not for the same unit. We build much of our logic out of building blocks, which we also want to be properly tested, but that doesn't mean we have to re-test them on the higher level of abstraction of a piece of code that composes them.

From that thought, it's maybe even a useful "design smell" you could watch out for if you encounter this scenario (in that you could maybe separate your building blocks more cleanly if you find yourself writing a lot of "internal" tests)?

Re:Is TDD Dead? (2014) by Jumziey on Wednesday August 26, 2020 @05:10PM (#24287298)
Isn't the idea with unit testing forgotten here? The point is to validate the blocks you build and use to build the program. In order to make sure you've done each block right you test them, manually or automated... Automated testing just is generally soooo much easier. If you work like that, and do not add test after y,ou've written large chunks of code you should have constructed your program so that there's no overhead in the test. Advanced test which does lots of setup and advanced calculations generally ain't the test fault, but the code itself that requires that complexity to be tested.

Wanna underline here that system tests are slow, unit tests are fast.

This said, i agre that you should throw away tests in a similar fashion as you do code. When it does not make sense don't be afraid to throw it, but have enough left to define the function of the code, in a documenting way. Let the code /tests speak! :D

Re:Is TDD Dead? (2014) by alexbanks on Wednesday August 26, 2020 @05:18PM (#24287389)
> Wanna underline here that system tests are slow, unit tests are fast.

System tests are slow but, in my experience, are far far far more valuable medium and long term. Unit tests are fast and relatively unhelpful.

Re:Is TDD Dead? (2014) by hderms on Wednesday August 26, 2020 @10:05PM (#24289474)
Imo the value of unit tests is partially a record for others to see "hey look, this thing has a lot of it's bases covered".

Especially if you're building a component that is intended to be reused all over the place, would anyone have confidence in reusing it if it wasn't at least tested in isolation?

Re:Is TDD Dead? (2014) by ptx on Wednesday August 26, 2020 @05:55PM (#24287744)
If the test suite took hours, couldn't part of the problem be that a lot of those tests should have been more focused unit tests? With small unit tests and mocking, you could run millions of tests in 3 hours.
Re:Is TDD Dead? (2014) by alexbanks on Wednesday August 26, 2020 @08:04PM (#24288746)
There were all kinds of problems with the test suite that could've been optimized. The problem was that there were too many to manage, and that deleting them was culturally unacceptable.

Lots of them made real DB requests. It's hard to get a product owner to justify having devs spend several months fixing tests that haven't been modified in 9 years.

Re:Is TDD Dead? (2014) by nkingsy on Wednesday August 26, 2020 @10:40AM (#24282890)
If it can cause a regression, it's not internal. My rule of thumb is "test for regression directly", meaning a good test is one that only breaks if there's a real regression. I should only ever be changing my unit tests if the expected behavior of the unit changes, and in proportion to those changes.
Re:Is TDD Dead? (2014) by geophile on Wednesday August 26, 2020 @01:52PM (#24285123)
This is wrong.

A well-known case is the Timsort bug, discovered by a program verification tool. Also well known is the JDK binary search bug that had been present for many years. (This paper discusses the Timsort bug, and references the binary search bug: http://envisage-project.eu/proving-android-java-and-python-s...)

In both cases, you have an extremely simple API, and a test that depends on detailed knowledge of the implementation, revealing an underlying bug. Obviously, these test cases, when coded, reveal a regression. Equally obviously, the test cases do test internals. You would have no reason to come up with these test cases without an incredibly deep understanding of the implementations. And these tests would not be useful in testing other implementations of the same interfaces, (well, the binary search bug test case might be).

In general, I do not believe that you can do a good job of testing an interface without a good understanding of the implementation being tested. You don't know what corner cases to probe.

Re:Is TDD Dead? (2014) by saagarjha on Wednesday August 26, 2020 @02:07PM (#24285322)
Using implementation to guide your test generation ("I think my code might fail on long strings") is fine, even expected. Testing private implementation details ("if I give it this string, does the internal state machine go through seventeen steps?") is completely different.
Re:Is TDD Dead? (2014) by geophile on Wednesday August 26, 2020 @04:24PM (#24286863)
Sure.
Re:Is TDD Dead? (2014) by yoden on Wednesday August 26, 2020 @02:08PM (#24285332)
That's not what he's saying. He's saying the test should measure an externally visible detail. In this case that would be "is the list sorted". This way the test will still pass without maintenance if the sorting algorithm is switched again in the future. You can still consider the implementation to create antagonistic test cases.
Re:Is TDD Dead? (2014) by Beldin on Wednesday August 26, 2020 @03:51PM (#24286504)
One of my colleagues helped find the Timsort bug and recently another such bug (might be the Java binary search, don't remember).

The edge case to show a straightforward version of that recent bug basically required a supercomputer. The artifact evaluation committee complained even.

So you can try to test for that only based on output. But it's gigantically more efficient to test with knowledge of internals.

Re:Is TDD Dead? (2014) by jeffffff on Wednesday August 26, 2020 @09:59PM (#24289449)
this sounds like a case where no amount of unit testing ever would've found the bug. someone found the bug either through reasoning about the implementation or using formal methods and then wrote a test to demonstrate it. you could spend your entire life writing unit tests for this function and chances are you would never find out there was an issue. i'd say this is more of an argument for formal methods than it is for any approach to testing.
Re:Is TDD Dead? (2014) by Beldin on Thursday August 27, 2020 @12:52AM (#24290225)
But once you've found the bug, you'd like to add a test case that prevents regression - a test case that doesn't require a supercomputer.

That might not always be possible - but if it is, the test would be based on implementation details.

Re:Is TDD Dead? (2014) by eithed on Wednesday August 26, 2020 @02:38PM (#24285722)
One doesn't need to have detailed knowledge of the implementation, but merely if provided initial state creates invalid output then we can write test for that. Though yes, having knowledge of implementation allows you to define the state that produces invalid result.
Re:Is TDD Dead? (2014) by the_af on Wednesday August 26, 2020 @10:50AM (#24282974)
> If it can cause a regression, it's not internal

Fair enough. And how do you know, before causing a regression, whether your test could detect one? In other words, how can you tell beforehand whether your test checks something internal or external?

Re:Is TDD Dead? (2014) by bmh100 on Wednesday August 26, 2020 @11:10AM (#24283143)
"External" functionality will be behavior visible to other code units or to users. If you have a sorting function, the sorted list is external. The sorting algorithm is internal. Regression tests are often used in the context of enhancements and refactorings. You want to test that the rest of the program still behaves correctly. Knowing what behavior to test is specific to the domain and to the technologies used. You can ask yourself, "how do I know that this thing actually works?"
Re:Is TDD Dead? (2014) by fiddlerwoaroof on Wednesday August 26, 2020 @11:44AM (#24283492)
Isn’t the point that internal functions often have a much smaller state space than external functions, so it’s often easier to be sure that the edge cases of the internal functions are covered than that the edge cases of the external function are covered?

So, having detailed tests of internal functions will generally improve the chances that your test will catch a regression.

Re:Is TDD Dead? (2014) by marcosdumay on Wednesday August 26, 2020 @12:26PM (#24284017)
> Isn’t the point that internal functions often have a much smaller state space than external functions

That's the general theory, and why people recommend unit tests instead of only the broader possible integration tests. But things are not that simple.

Interfaces do not only add data, they add constraints too. And constraints reduce your state space. You will want to cut your software over the smallest possible interface complexity you can find and test those, those pieces are what people originally called "unities". You don't want to test any high-complexity interface, those tests will harm development and almost never give you any useful information.

It's not even rare that your unities are composed of vertical cuts through your software, so you'll end up with only integration tests.

The good news is that this kind of partition is also optimal for understanding and writing code, so people have been practicing it for ages.

Re:Is TDD Dead? (2014) by bmh100 on Wednesday August 26, 2020 @01:13PM (#24284581)
I agree that they would help in the regression testing process, especially in diagnosing the cause. However, I think those are usually just called "unit" tests, not "regression" tests. For instance, the internal implementation of a feature might change, requiring a new, internal unit test. The regression test would be used to compare the output of the new implementation of the feature versus the old implementation of the feature.
Re:Is TDD Dead? (2014) by ska on Wednesday August 26, 2020 @12:09PM (#24283808)
Having regression tests greatly improves your chances of catching a regression.
Re:Is TDD Dead? (2014) by amalcon on Wednesday August 26, 2020 @03:56PM (#24286565)
Worth noting that performance is an externally visible feature. You shouldn't be testing for little performance variations, but you probably should check for pathological cases (e.g. takes a full minute to sort this particular list of only 1000 elements).
Re:Is TDD Dead? (2014) by the_af on Wednesday August 26, 2020 @02:13PM (#24285407)
> "how do I know that this thing actually works?"

Agreed, but how do you know your test tests this? Or to re-phrase it: why would you even write a test that doesn't test this?

Re:Is TDD Dead? (2014) by nkingsy on Wednesday August 26, 2020 @12:10PM (#24283844)
For bugfixes, I just write a failing test.

For features, I need to take the time to think of required behavior. If I just focus on the implementation, the tests add no documentation and I'm not forced through the exercise of thinking about what matters.

Re:Is TDD Dead? (2014) by the_af on Wednesday August 26, 2020 @02:16PM (#24285440)
> If I just focus on the implementation [...]

Agreed, but why would you even write those tests to begin with?

Re:Is TDD Dead? (2014) by neallindsay on Wednesday August 26, 2020 @01:27PM (#24284802)
> Aren't a huge part of tests to prevent regression?

Just a quibble: I would argue that a huge benefit of tests is preventing regression, but that's a very small part of the value of tests.

The main value I get out of tests is informing the design of the software under test.

* Tests are your straight-edge as you try to draw a line.

* They're your checklist to make sure you've implemented all the functionality you want.

* They're your double-entry bookkeeping to surface trivial mistakes.

But I think I mostly agree with your point. I delete tests that should no longer pass (because some business logic or implementation details are intentionally changing). I will also delete tests that I made along the way when they're duplicating part of a better test. If a test was extremely expensive to run, I suppose I might delete it. But in that case I would look for a way to cover the same logic in tests of smaller units.

Re:Is TDD Dead? (2014) by a1369209993 on Wednesday August 26, 2020 @11:38PM (#24289901)
All legitimate tests are[0] regression tests. TDD, to the extent that it's actually useful, is the notion that sometimes the bug being regression-tested is a feature request.

Edit: 0: I guess "can be viewed as" if you want to be pedantic.

Re:Is TDD Dead? (2014) by shados on Wednesday August 26, 2020 @05:54PM (#24287731)
> Aren't a huge part of tests to prevent regression?

Depends on the kind of tests. Old school "purist" unit tests are meant to help you verify the correctness of the code as you're writing it. Preventing regressions is better left to integration tests and E2E tests, or smoke tests. Alternatively to "unit tests" if your definition of "unit" is big enough (in which case it only works within the unit).

It's totally fine and common to write unit tests that are not meant to catch bugs of significant refactors. If you do it right, they should be so easy to author that throwing them away shouldn't matter.

Re:Is TDD Dead? (2014) by hendershot on Wednesday August 26, 2020 @06:03PM (#24287810)
Integration, E2E, and smoke tests are generally slow, flakey, hard to write. They should not cover/duplicate all the cases your unit tests cover.

They are good at letting you know all your units are wired up and functioning together. In all the codebases I've ever worked in, I would feel way more comfortable deleting them vs deleting the unit tests.

Re:Is TDD Dead? (2014) by iateanapple on Wednesday August 26, 2020 @06:16PM (#24287935)
> Integration, E2E, and smoke tests are generally slow, flakey, hard to write.

This is not really true anymore in a modern system.

I can spin up an entire cluster to mirror prod - including databases and all - and run approx 10k integration tests all in under 5 minutes.

Re:Is TDD Dead? (2014) by hendershot on Wednesday August 26, 2020 @06:54PM (#24288239)
Why would you want to? when the same unit test coverage will run under 1 minute, and be smaller easier to understand/change tests and can all be done on your laptop.

it all depends on your definition of unit/integration, what I am talking about as unit tests you may very well be talking about as integration tests...

one of the main points I was making is you shouldn't have significant duplication in test coverage and if you do, I'd much rather stick with the unit tests and delete the others.

Re:Is TDD Dead? (2014) by iateanapple on Thursday August 27, 2020 @05:32AM (#24291703)
> Why would you want to?

Because they catch more bugs than unit tests, are easier for our product team to understand, and rarely break when refactoring.

Even a simple business flow like registering a new user will touch half a dozen systems.

5 or 6 integration tests can cover this flow far better than 100 unit tests.

> and be smaller easier to understand/change tests

That’s not my experience at all.

Unit tests are generally much harder to understand and need to be changed much more frequently.

Where unit tests help in my experience is:

A) in pinpointing where in a complex bit of logic the bugs are.

B) for generic libraries and building blocks where you don’t know exactly how your users will actually use them.

Re:Is TDD Dead? (2014) by shados on Thursday August 27, 2020 @09:27AM (#24293451)
> Unit tests are generally much harder to understand and need to be changed much more frequently.

Changed more frequently, yes.

Harder to understand is usually because they're not-quite-unit-tests-claiming-to-be.

Eg: a test for function that mocks some of its dependencies but also does shenanigans to deal with some global state without isolating it. So you get a test that only test the unit (if that), but has a ton of exotic techniques to deal with the globals. Worse of all worlds.

Proper unit tests are usually just a few line long, little to no abstraction, and test code you can see in the associated file without dealing with code you can't see without digging deeper.

Re:Is TDD Dead? (2014) by softwarefounder on Wednesday August 26, 2020 @04:54PM (#24287158)
Yes. I believe you shouldn't delete tests.

After all, one of the best reasons for tests is to be able to refactor code confidently.

Re:Is TDD Dead? (2014) by CraigJPerry on Wednesday August 26, 2020 @05:43PM (#24287638)
If you can refactor (make a commit changing only implementation code, not touching any test code) and the tests still pass then you’re probably fine.

If you’re changing tests as you change the code you’re not refactoring. You have zero confidence that your changed behaviour and changed test didn’t introduce an unintended behaviour or regression.

So many developers miss this in my experience.

Re:Is TDD Dead? (2014) by jeffffff on Wednesday August 26, 2020 @10:12PM (#24289502)
if you can refactor without touching your tests and your tests still compile afterwards either the refactor was extremely trivial and didn't change any interfaces or you only had end to end tests.
Re:Is TDD Dead? (2014) by hnick on Thursday August 27, 2020 @01:19AM (#24290365)
I think the point is that if you have to change a test to make it pass or run after refactoring, it is not useful as a regression test. By changing it you might have broken the test itself so you have less confidence.

There is also the question of what a unit is. If you test (for example) the public interface of a class as a black box unit, you can refactor your class internals as much as you want and your tests don't need to change. You have high confidence you've done it correctly. At this point adding more fine-grained tests inside the class seems like more of a compliance activity than one that actually increases confidence, since you probably would've had to change a bunch of them to make them work again anyway.

Re:Is TDD Dead? (2014) by jasonwatkinspdx on Wednesday August 26, 2020 @03:00PM (#24285962)
Personally the way I'd phrase it is you need to refactor your tests just like you'd refactor the app code, but even looking at doing that independent of any app code refactoring.