Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How/what to mock in BDD

Tags:

I know one of Dan North's intentions in devising BDD was to move the vocabulary away from the complexity of the test domain. However, in implementing an outside-in approach, it seems we still require some understanding of mocked behavior (or stubbed behavior, if you prefer). North suggests in this video that if I start with the outermost domain objects and work my way inward, I mock collaborators as I discover them and later replace them with the proper implementations. So in the end, I end up with a set of end-to-end tests.

Martin Fowler seemed to see it a little differently in this blog post when he defined two camps of TDD: "classical TDD" which uses real objects where possible and a mock when necessary, and "mockist TDD" which prefers mocks in most situations. He saw BDD as tending toward the latter. I.e, that at the end of developing a feature, the "mockist" approach would leave mocks in the actual tests (sorry to use that word in a BDD discussion).

In fairness, both materials are years old, and perhaps things became clearer as BDD evolved along the line between being applied at the unit level and the acceptance level.

But my question for the community is basically: when my story is complete, how much of an end-to-end test should my scenarios actually be? North explains that BDD requires abstractions. For example, when I'm testing login behavior, then my scenarios will detail what the login process means. However, when I'm doing some other scenario that requires but isn't about login, I don't want to have to do those steps over and over. I want an easy abstraction that simply says "Given I'm logged in," so I can go execute my other behavior.

So it seems my approach to abstraction will be in that I mock certain collaborators (or provide a "test double"), and some scenarios may use them more than others. For example, do I always mock out external resources, such as a DB or a mail server?

Perhaps I'm asking the wrong question. BDD is all about communication, shortening the feedback cycle, and discovering what you don't know. Maybe what-and-what-not-to-mock is an irrelevant question, so long as the behavior we're interested in actually works. I'm curious what others' approaches here are.

like image 773
Ryan Nelson Avatar asked May 01 '12 18:05

Ryan Nelson


People also ask

What is mock and how do you use it?

Mock is a method/object that simulates the behavior of a real method/object in controlled ways. Mock objects are used in unit testing. Often a method under a test calls other external services or methods within it. These are called dependencies. Once mocked, the dependencies behave the way we defined them.


2 Answers

To me BDD allow me to verify that I've built the right thing. That means that If I plug my application on a real database and use the real UI, it should behave correctly. That's the end to end you are talking about.

Now if my plug my application on a in memory storage and I talk to the app through its API level (so just below the UI). I will expect it to behave exactly the same way.

Now that's the thing, we need to be clear on what we mean by behaviour, what is the behaviour we are interesting in when we do BDD.

In my case, if I start from a user story and write scenarios, i'm interested mainly in the behaviour that goes through my application API, service layer, domain entities, helper, etc...mainly I'm not so much interested in what will happen in the UI nor the database. The real meat is all the code written on the server side. That's the behaviour i'm interested in. If you think like that it makes sense to get rid of the UI and the DB, because we don't care about these guys. The expected Behaviour of the UI is to display the Data that my application give. The UI is a dumb thing. The expected behaviour of the DB is to store and retrieve entities that my application give or want. That's also a really dumb thing. Now everything else, that's where all the smartness is and I'm responsible for.

So I'll happily run my BDD scenarios without a UI and using an in memory version of my repositories. The bonus I get from that is really really fast, focused and maintainable tests.

Regarding the UI and the DB, I would write javascript unit tests to test the behaviour in there, today some UI can have lots of display logic to hide and show stuff, but that kind of behaviour is different from the behaviour in my user stories bdd scenarios (they should not talk about the UI).

For the DB I'd write integration tests just to check that my real repositories are able to read and write stuff on the DB.

And finally I'd write just a few end to end tests to check everything is OK when wired together.

like image 120
foobarcode Avatar answered Sep 29 '22 04:09

foobarcode


I think that the key is to focus on the B of BDD - behaviours.

At the moment I tend to ignore the UI elements and Mock away the persistence layers - after all these days there is little if any business logic in those layers (we tend to just bind object models directly to the UI or DB using pre-existing and heavily tested frameworks).

As way of an example, in a recent (simple) WPF application that I was building: the acceptance tests use the ViewModel's as the entry/outside point of the application - and everything down from the data Repositories was mocked. All the rules and logic of the application existed somewhere between the two - and really, those are the application's behaviours that needed to be specified and tested.

like image 26
SaxonMatt Avatar answered Sep 29 '22 02:09

SaxonMatt