Live data from Hacker News

Prefer Fakes over Mocks

tyrrrz.me

81–90 of 125 posts

Re: Prefer Fakes over Mocks

#81
I watch more people overcomplicate their lives when it comes to unit testing. The problem discussed in this article is not one of mock vs. fake its actually about how this individual chose to engineer their application.

First I'll introduce some axioms...

1. Mixing unit and integration testing is not ideal. If you are doing unit testing focus on verifying the code paths within the unit. When considering the collaborators focus on the finite number of states that are most likely to occur.

2. (I know this is contentions) Design your code so that it is easy to unit test. It'll be ok I promise. In almost all cases code designed for easy unit testing is synonymous with well engineered code

Imagine this python...

```

def get_a_file_and_do some_stuff(path):

    d = dict()    

    with open(path, 'r') as file:

      for line in file:

          d[line] = d.get(line, 0) + 1

    # a bunch of code that does something with this dictionary

    return result
```

The above is miserable to test with mocks. You end up trying to man handle the file object. Its not fun.

```

def get_a_file_and_do some_stuff(path):

    d = convert_path_to_dictionary(path)

    # a bunch of code that does something with this dictionary

    return result
```

With the simple flick of the wrist I can now trivially mock out "convert_path_to_dictionary(path)" and I only ever have to work with dictionaries.

So you might say "but but what about the file dictionary code. are you going to test that?" Probably not and if experience is any indicator I'll never have an issue with it. The edge cases and regressions will all lie in the custom business logic executed on the dictionary.

I see engineers make their lives enormously difficult to live up to some unachievable standard. Often that standard yields very little value in excess of a much simpler approximation

Re: Prefer Fakes over Mocks

#82
post #76
post #13

A tangent, and somewhat philosophical: is "The primary purpose of software testing" really "to detect any potential defects in a program before it reaches its intended consumers"? I would argue that whilst that is a commonly held belief, and certainly true for some tests of business logic, the main value and reason for testing is to allow developers to confidently make changes to existing code. In my experience user…

I prefer to express it as the purpose of tests is to ensure something never changes. I don't care how future maintainer touches the code so long as given this set of inputs this is the output.

People are touching the code because something has to change. Typically in the service of a new business case.

Re: Prefer Fakes over Mocks

#83

Earlier quoted context omitted.

>> .. fully functional fake of the original class. So they are coupled to the implementation of the object in any case!

I’d say rather that they’re coupled to the behaviour of the object.

Not exactly - they are coupled to the interface contract. The behavior can be very different.

Re: Prefer Fakes over Mocks

#84

I watch more people overcomplicate their lives when it comes to unit testing. The problem discussed in this article is not one of mock vs. fake its actually about how this individual chose to engineer their application. First I'll introduce some axioms... 1. Mixing unit and integration testing is not ideal. If you are doing unit testing focus on verifying the code paths within the unit. When considering the collabora…

"All problems in computer science can be solved by another level of indirection" - David Wheeler

I agree with you for most part. Mixing unit tests with integration tests is a recipe for failure.

Re: Prefer Fakes over Mocks

#85
There is another advantage of good fakes: they often can be shipped in production as your demo mode. I've seen cases where when of the most important new features to marketing was just make some part of the fake more useful in production. Sometimes because there is a show coming up and the demo mode is what customers will see. Sometimes because the trainers want a better simulation of some issue.

In some cases the fake is a lot more complex than the real implementation. (I worked on a diagnostic tool, the real implementation "just" needed to send/receive bytes, the fake needed to understand the bytes and return responses)

Re: Prefer Fakes over Mocks

#86
post #50

I'm a little surprised this article and none of the contents here at the time of this writing mentioned inheritance. The core reason I find OOP to be superior for most classes of business application development in general—and web development in particular—is that external dependencies and other high cost interfaces can be delegated to their own method or instance variable then called. In general, I avoid inheritance…

The benefits you describe for OOP can be achieved in FP through function composition. DI doesn't have to mean you set up a container, you know. > I know that something akin to this is theoretically possible in functional languages, but I've found that in practice it's more difficult. Could you explain what you think is hard about it?

Function composition doesn't spring to mind when I think fakes/mocks/testing. As a long-time functional programmer, the things I'd reach for are:

Higher-order functions: rather than taking a 'service object' as an argument, and calling one or two of its methods, we can accept the methods/functions we need as arguments. Tests can pass in their own functions, which looks a lot like mocking but doesn't need any tricks or frameworks. This is the easiest approach for simple cases, but incurs lots of boilerplate as it's used more and more.

Records: these are name/value collections (think '{foo: bar, ...}' in JS). Since the values can be functions, they're pretty much objects; but we can swap out these values without having to define classes, etc. We can use these just like 'service objects' in OOP.

Type classes/interfaces: these define certain operations/methods that can be performed on a given type, even if that type's generic. They're essentially records like above, but chosen by the compiler based on the type; some languages (e.g. Agda, Idris, Scala) also allow overrides to be taken from the current scope.

Domain-specific languages: we treat the methods/operations of our API as if they're builtin-functionality of some 'embedded' language. When we use such functionality, the result is a program for that embedded language. We can run these programs by defining an "interpreter" (a function which implements each of these operations); we can define a 'real' interpreter and a test interpreter. This is the most hardcore, and usually benefits from some framework for doing the necessary plumbing. I wouldn't recommend it as a first step, but I've had success doing this with Haskell's Polysemy library; another popular library is Haskell's 'Monad Transformer Library' but I've not used that myself.

Re: Prefer Fakes over Mocks

#87
post #57
post #13

A tangent, and somewhat philosophical: is "The primary purpose of software testing" really "to detect any potential defects in a program before it reaches its intended consumers"? I would argue that whilst that is a commonly held belief, and certainly true for some tests of business logic, the main value and reason for testing is to allow developers to confidently make changes to existing code. In my experience user…

Let's look at it a different way and start with the assumption that in all cases we're delivering reliable software, it's just a question of how we get there. The simplest way of doing this is to write code with good practices then do a load of manual system testing to find bugs (system testing including user acceptance testing in this example). This is basically what most people were doing 20 years ago. This can wor…

It's also a question of the there you want to get to. And how fast you want to get there.

Testing can be about a lot more than just catching bugs. It can be about any measure of reality that can be turned into useful feedback to make developers more aware.

Testing is like the headlights on your car - they're useful even in absence of bugs.

Re: Prefer Fakes over Mocks

#88
Just to comment on the topic at a higher level:

I'd like to add my own thoughts to this discussion, but feel it's the kind of topic that blows up into a mess/mass of opinion such that adding another comment just adds to the dogpile; after a certain critical mass, no-one really reads the majority of comments before commenting themselves, and a positive feedback of repetition begins.

Maybe if the discussion was broken into narrow sub-topics this could be fixed?

Re: Prefer Fakes over Mocks

#89
post #80
post #74

Earlier quoted context omitted.

> But that is an implementation detail. Only the BulkPurchaseDiscountStrategy knows whether it's 9 or 10 that's the trigger. Language is poor, but I think there is consensus on what "implementation detail" means, and I don't think that's it. Whether it's 9 or 10 is customer facing behaviour. It's behaviour that might come from your marketing team or product owner or whatever, but it is outward facing. It is something…

But the price break is a requirement that I expect to change. Today it is 10. Tomorrow someone looks at the production process the machines give groups of 11, so the bulk discount should be multiples of 11 (if you order 12 you get 11 at the bulk rate and 1 and the regular price). Then next week management says small orders are too hard to serve, and so the minimum bulk order is 100, but bigger discounts if the total…

If your requirement changes so that the price break is at 11 rather than 10, then I expect the process to go:

* Change the (or shared test code) that has the price break specification from 10 to 11 * Run it, see the failures * Update the source code appropriately

The updated source code is the same in both our cases. In my case the changed test code is testing the ShoppingCart interface and in yours it's a unit test of something lower down. There's not extra cost, it's just in a different place.

Or are you suggesting that your tests don't know about 10 vs 11 at all? There's a reasonable architecture where such data comes from outside your system, and the spec for your system is 'price breaks should reflect this data input' and then you mock that data input and test it, but that's a different thing.

Re: Prefer Fakes over Mocks

#90
post #56

Earlier quoted context omitted.

Um, no. The test needs to know the expected system behaviour, given that dependencies are properly wired & behave as expected. You can argue that "it no longer tests just the ShoppingCart in isolation" and that would be true; but whether that's a downside or an upside is up for debate IMO (and more often than not it really is an upside). [edit] In other words, you don't test that "if discount is 10%, adding item to s…

I would argue then that this isn't Unit Testing, it's some other kind of testing. One of the problems I'm dealing with at the moment is exactly this problem - someone's gone and written a whole ton of tests which involve spinning up pretty much everything short of the DB, and now writing a small test that just tests the behaviour of one class is exceedingly difficult.

You're right, it's not unit testing. I call it integration testing, some people call it functional testing.

The question is why you want to test that one class? We do have some modules in our (elixir) system that are 'thoroughly' unit tested. These are modules that are algorithmically complicated so testing them in isolation is useful. Most of the code is tested in logical chunks though.

Post reply on HN