Live data from Hacker News

Software testing, and why I'm unhappy about it

nhaehnle.blogspot.com

71–76 of 76 posts

Re: Software testing, and why I'm unhappy about it

#71
post #17

I have a lot of bitter things to say about automated testing, having spent 14 years of my life trying to knead it into a legitimate profession, but here's the most significant: You test case is more useless than a turd in the middle of the dining room table unless you put a comment in front of it that explains what it assumes, what it attempts, and what you expect to happen as a result. Because if you just throw in s…

Which is funny as the purpose of testing is to explain to other other developers what the code under test assumes and what should be expected of it under various conditions. It is documentation. If you have to document your documentation, you might be missing something fundamental in how you are writing your first order documentation. Not to mention that in doing so you defeat the reason for writing your documentatio…

The test plan is the documentation. That people are cutting corners is unfortunate.

A test must be reproduceable. If it is not, is not a test.

Re: Software testing, and why I'm unhappy about it

#72

Earlier quoted context omitted.

Code as documentation feels like a good idea because code is the only reliable source of truth. But it also assumes that code can comprehensively express all assumptions and other info, which sounds more like wishful thinking. Auto-generated API docs combined with handwritten documentation that covers what can't be expressed in code and includes some useful examples seems like the right approach to me. In practice th…

I'm not sure if you're saying that rust stdlib docs do this but documentation where all the examples are themselves runnable as tests and included in the CI test suite solves so many problems.

Not just the stdlib, the documentation tool itself supports this, so it's the case for any Rust package that writes documentation.

Re: Software testing, and why I'm unhappy about it

#73
post #10

The author's problem is pretty simple: the test repo is required for pre-merge tests to pass, but it can be updated independently, without having pre-merge tests pass. And the answer is pretty simple: pin the specific test repo version! Use lockfiles, or git submodules, or put "cd tests && git checkout 3e524575cc61" in your CI config file _and keep it in the same repo as source code_ (that part is very important!). T…

> And the answer is pretty simple: pin the specific test repo version! Use lockfiles, or git submodules, or put "cd tests && git checkout 3e524575cc61" in your CI config file _and keep it in the same repo as source code_ (that part is very important!).

Indeed. Where I work we have a bunch of repos, but they always reference each other via pinned commits. We happen to use Nix, with its built in 'fetchGit' function; it's also easy to override any of these dependencies with a different revision. For example:

  { helpers ? import (fetchGit {
      url = "git://url-of-helpers.git";
      ref = "master";
      rev = "11111";
    })
  , some-library ? import (fetchGit {
      url = "git://url-of-some-library.git";
      ref = "master";
      rev = "22222"
    }) {}
  }:
  helpers.build-a-service {
    name = "my-service";
    src  = ./src;
    deps = { inherit some-library; };
  }
This is a function taking two arguments ('helpers' and 'some-library'), with default arguments that fetch particular git commits. This gives us the option of calling the function with different values, to e.g. build against different commits.

We run our CI on GitHub Actions, which allows some jobs to be marked as 'required' for PRs (using branch protection rules). The normal build/test jobs use the default arguments, and are marked as required: everything is pinned, so there should be no unexpected breakages.

Some of our libraries also define extra CI jobs, which are not marked as required. Those fetch the latest revision of various downstream projects which are known to use that library, and override the relevant argument with themselves. For example, the 'some-library' repo might have a test like this:

  import (fetchGit {
    url = "git://url-of-some-library.git";
    ref = "master";
    # No 'rev' given, so it will fetch 'HEAD'
  }) {
    # Build with this checkout of some-library, instead of the pinned version
    some-library = import ./. {};
  }
This lets us know if our PR would break downstream projects, if they were to subsequently update their pinned dependencies (either because we've broken the library, or the downstream project is buggy). It's useful for spotting problems early, regardless of whether the root cause is upstream or downstream.

Re: Software testing, and why I'm unhappy about it

#74
post #68

Earlier quoted context omitted.

If a unit test covers function f(a,b) to ensure it always returns the right answer in the domain of a,b But a developer looks at f(a,b) and realises a new implementation could be 10x faster. The developer re-writes the function, the tests still pass. Without that test they couldn't be sure their rewrite didn't break the expected behaviour. What you're talking about is changing interfaces and structure when refactorin…

> If your unit tests are not testing discrete units, instead testing the combined behaviour of many units This is a very naive idea of unit tests. In the real world applications have a dependency hierarchy with more than two levels. If you want to test anything other than the leaves in that hierarchy you are by definition testing the behaviour of many units. Sounds like what you're saying is that unit tests are only…

> Thay would also make unit tests quite useless

Not so. Their use is to aid refactoring of those nodes. Also the leaf node can contain calls to other code (leafish) if that code too is unit tested.

They're the sum of their parts.

Integration tests used lightly to test specific integration occurs (ie f() not only meets X constraint but calls y() in a certain way to do so) if that's important.

The fact that most codebases unit tests are a fragile mess, and that many devs find tests a burden highlights just how poorly the topic is understood.

Re: Software testing, and why I'm unhappy about it

#75
post #68

Earlier quoted context omitted.

> If your unit tests are not testing discrete units, instead testing the combined behaviour of many units This is a very naive idea of unit tests. In the real world applications have a dependency hierarchy with more than two levels. If you want to test anything other than the leaves in that hierarchy you are by definition testing the behaviour of many units. Sounds like what you're saying is that unit tests are only…

> Thay would also make unit tests quite useless Not so. Their use is to aid refactoring of those nodes. Also the leaf node can contain calls to other code (leafish) if that code too is unit tested. They're the sum of their parts. Integration tests used lightly to test specific integration occurs (ie f() not only meets X constraint but calls y() in a certain way to do so) if that's important. The fact that most codeba…

> Their use is to aid refactoring of those nodes

Sure. But there are codebases where leaves are less than 20% of the code. Yet testing preachers are saying that unit tests are the most important part (e.g. Martin Fowler's Testing Pyramid). Though again, they use a different definition of unit tests: everything is a unit if you mock enough.

> how poorly the topic is understood

Well, at least one of the reasons is that people focus too much on test classification. You need to decide what is important to test, how is just implementation detail. If that's your approach, you'll realize that you're getting the most value from integration tests. The only downside to this is losing Testing Church membership. But that happens when you apply logic and reason.

Instead, everybody decides that "we write unit tests", without thinking what needs to be tested and recognizing limitations of unit tests.

Re: Software testing, and why I'm unhappy about it

#76
post #28

Earlier quoted context omitted.

So i understand correctly, that your position is "code is the documentation"? Over time im inclined to value human written documentation. Especially when things involve integrations of multiple systems. I had real cases, where two parties point at code and say their code is correct. And in isolation code looks correct. But when time comes to integrate these systems. It breaks. And then if you have human readable docu…

Same. I’m sick of people escaping writing documentation by saying that "code is the doc" and in the meantime, writing unreadable code abstracted over dozens of code files. They almost convinced me somewhere in my career. But the hard truth I learnt is that most people are saying this because they aren’t capable of verbalizing what they are programming. If your "code is doc", it should be extremely easy to add a littl…

> They almost convinced me somewhere in my career. But the hard truth I learnt is that most people are saying this because they aren’t capable of verbalizing what they are programming.

I'd say that's true, and it's worth noting at this point that expressing certain things in natural language is hard. The strict rules of programming languages mean that you can reason about programs to a complexity level that would otherwise be unreachable. Notation as a tool of thought. The corollary is that there may not be a simple natural language equivalent of the code you're writing, and that adding documentation might be more effort than it's worth.

Post reply on HN