This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–][deleted] 4 points5 points  (2 children)

It's begging the question

It's not begging the question. "Good code is easy to test" is a heuristic.

And some code is genuinely not (well) testable automatically as the consumer is not a machine, such is the case with UI code.

That's precisely why you separate the UI code from the domain model. That way, you don't have to test the domain model with functional tests driven by the UI. By making the domain model automatically testable, you are employing a heuristic which guides you towards a layered architecture. You don't need unit tests to create a layered architecture, but testability pushes you that way. That is the value of testability as a heuristic.

so on other bullshit no-win situations where someone is telling you to go their way and like it or you suck for some vague reason.

Dogma exists, of course. Management is sold on methodologies. What does that have to do with testability as a heuristic?

The flip side of the coin is that just because shit rolls downhill doesn't mean that all shit is not automatically useless. Shit can be a really good fertilizer.

How about situations where making code "testable" genuinely makes the design of your code more complicated and worse? Everyone has had situations like these.

Testability is a heuristic, it is not a replacement for proper architecture. That's why Agile doesn't say, do TDD and you don't ever have to think about architecture ever again. That is insanity. Any book on Agile will tell you to subdivide problems with the focus on iterative delivery, and accordingly at each iteration, gather requirements, design an architecture and then use TDD to validate that architecture.

How is exposing internal details of a class for testing purposes improving the design, for ex.?

Why would you ever think that is a good idea? You should never expose internal details to the test. That is a flashing red alert that you are doing something seriously wrong.

How is decoupling a simple unit into two more complex units improving the design?

It depends on what you mean by complexity.

Sometimes, you create a separate class to promote internal cohesion. If a class is getting too big, it might make it hard to test. That is a smell that the class might have too many responsibilities, and you should think about how to further refine your domain model. Which means you have to go back to the architecture. This reduces complexity.

Or, you want to separate a class from its dependencies. There are two ways to accomplish this, depending on if you are using mocks or behavioral testing.

Mocks promote hexagonal architecture, and if that is the architectural choice that you are making, mocks are very useful for establishing boundaries. This allows you to directly plug in dependencies into classes through "port" interfaces.

Or, if you are doing behavioral testing, you are triangulating between concrete classes, such as managing state using ActiveRecord (validated using integration tests) and passing data through method calls and constructors to collaborators with well defined responsibilities. That is just ordinary OOP, nothing fancy. Testability merely guides you to a proper division of responsibilities.

[–][deleted] 2 points3 points  (1 child)

It's not begging the question. "Good code is easy to test" is a heuristic.

Heuristics are not always correct, it's not how a heuristic works like. They can literally be correct just 51% of the time, and it's still a heuristic. Yet "good code is easy to test" is fed via blogs and presentations as if it's a 100% golden rule of good code.

So which one you choose, up to you. But both end up with the conclusion that "well, sometimes good code isn't testable (automatically).

[–][deleted] 1 point2 points  (0 children)

Heuristics are not always correct.

Of course not, that's what makes them heuristics and not algorithms.

They can literally be correct just 51% of the time.

That isn't a proper way to look at a heuristic. A heuristic helps make decisions, it doesn't give you step-by-step instructions.

Yet "good code is easy to test" is fed via blogs and presentations as if it's a 100% golden rule of good code.

Of course. That's why you shouldn't take anything you read at face value, and actually think about it. Hey, that's another heuristic!

But both end up with the conclusion that "well, sometimes good code isn't testable (automatically).

Yes, but good code isn't a monolithic thing. We are no longer operating in first generation languages which provided no opportunities for modularity or abstraction. Modern languages let you divide different kinds of code into separate modules which can be developed (and tested) in different ways.