Hacker News new | past | comments | ask | show | jobs | submit login

What do you mean? If you compose functions (and objects) together then you have to mock things out one way or another, inject them in, and assert that your code interacts correctly with its dependencies.

This doesn't seem like a go specific issue but an engineering one.




In Java or Python you do not normally need write a test case for “if this dependency fails, it will be propagated to the caller.” In Go you have to do this or your line/branch coverage will be abysmal.

Java and Python mocking is also a lot more lightweight; you don’t have to generate mocks ahead of using them, regenerate them when the interface changes or work generation into your build process, etc. Richer reflection APIs make it a pretty casual handful of characters to mock something out.


> In Go you have to do this or your line/branch coverage will be abysmal.

If you're writing tests to improve coverage numbers then maybe you're motivation is wrong.

In most languages with automatic exception propagation you never know what exceptions can be thrown. Is it any different from not testing?


It would be interesting to know what errors we might get, but unit testing an error return branch doesn't tell us that. It tells us that any non-nil error will be returned.


> In Go you have to do this or your line/branch coverage will be abysmal.

If reliability is critical, having explicit error handling and coverage tools which expose error conditions which haven't been tested is very helpful.


I make a sequence of calls during the service of a request. If any one of them fails I want to stop and return the error to the caller.

Having to check this in the particular case of every call at every later underlying every handler, does not make my software more reliable in than when it is simply guaranteed in general.


Explicit error handling can improve reliability in some circumstances, because it highlights corner cases which are easy to ignore otherwise.


If your Java code doesn't test exceptions that could be thrown, your branch coverage is equally abysmal and your tools aren't telling you that.


The language's exception facility does what it says. We don't need a unit test to prove that in every particular case, any more than we need a unit test to establish that the language correctly carries out our assignments or function calls.


You picked two languages (Java and Python) with extremely weak guarantees about disposal of resources when exceptions are thrown. Any time I acquire a non-trivial resource I must make sure it's disposed of properly, via a `close` etc. method. (And these are most cases of interest; acquiring trivial resources e.g. memory shouldn't need error handling in Go either.)

This isn't theoretical. I review a lot of Python code and I would say in over 20% of cases I see a try block with a `finally` longer than two lines, it mistakenly uses a variable that might not be set when an exception is thrown earlier than the writer expected.


When a controller calls a couple of gateways and a database access layer, it is almost never holding resources. I would agree that testing error handling is more interesting when there are resources to clean up or fallback logic to implement. That's just very rarely the case. Mostly I just need to bail out of the request.


Java has try-with-resources and Python has context managers, I wouldn't consider either of them harder to use correctly than defer.


I'm not talking about defer at all. The contrast would be C++'s RAII.


> regenerate them when the interface changes

You don't need to do this in Go either. Embed the interface type in your mock type. You only need to implement functions that will be called in the function under test.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: