Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

Predicate: I\'m brand new to BDD / TDD, but I\'ve done my homework. I\'m trying

ID: 642144 • Letter: P

Question

Predicate: I'm brand new to BDD / TDD, but I've done my homework.

I'm trying to put everything I've read / learned into practice with VS2010, SpecFlow and NUnit. Things are working, but it's quickly becoming a chicken / egg scenario within a blur of unit and acceptance tests. I hope solving these BASIC questions will make everything click.

From my reading, I expected to:

Write a Feature
Define Acceptance Tests that fail
Define Unit Tests that fail
Make Unit Tests pass
Now the Acceptance Test pass
Write the next Feature
That all makes perfect sense, I'm just having a hard time seeing what's what in code...

In practice:

Write a Feature with Scenarios - fine.
Generating Step Definitions - fine.
Ahhh.
Does completing the step definitions (providing context in GIVEN, setting things up in WHEN and making assertions in THEN) constitute a completed acceptance test? Do you write out classes and methods here first as if you'd defined them already, and generate skeleton code via the IDE? Presumably the assertion needs some kind of implementation to work, but then the implementation code won't have been unit tested? Ahhh.

I've looked at a number of example projects and codebases, but as they're all complete there's little sense of ordering in terms of the development process.

Any clarification of steps, examples, etc. would be great!

Explanation / Answer

Your order is wrong, methinks:

Define Acceptance Tests that fail
Define Unit Tests that fail
Make Unit Tests pass by writing the logic required for the feature
Make the Acceptance Test pass by integrating the logic into the existing system
Repeat with the next defined requirement
Basically, in both TDD and BDD, you always define what your new code should do before you write a line of that code. So, breaking it down, the real process is:

Read the requirements for the next story, and break it down into individual pieces that can be defined in SpecFlow as assertions using "Given", "When" and "Then" clauses.
Write the first assertion into SpecFlow. This is your "acceptance test" and it will fail because the behavior is not in the system.
"Drill down": Identify the code object that is most directly interacted with from outside the system's boundaries, which must exhibit the newly-defined behavior. That object does not necessarily exist in the current codebase. Write a test that asserts the object exhibits the desired behavior. Repeat; find the object(s) that the one you just tested must interact with to exhibit the defined behavior. Define tests that assert these objects do what they need to. Repeat until you identify one or more lines of actual code within a method which do not yet exist or which must change in order to begin exhibiting the behavior. Along the way, tests that must touch another object, the network, file system, DB, etc to have value are "integration tests"; tests that can operate within the boundary of a single class, or that have value given "test data" in the form of mocked objects, are "unit tests".
Now, the coding of the actual feature begins. Do what you have to to make the tests you wrote, and all other tests in the system, pass; unit first, then integration, then acceptance. It is not unheard of to write a code that passes first try; that indicates either a bad thing (you didn't make the correct assertions; go back to step 3) or good (the behavior you need already exists; move on). It's also not unheard of to make a change that passes a new test but fails an old one; either you made an incorrect change, or the assertions of the old test are now incorrect in light of the new requirement. It's your job to determine which.
Once everything is "green", refactor the code you wrote to pass the tests; organize it, merge code blocks that do the same thing, adhere to good coding patterns. Make sure all the tests still pass, of course.
Repeat from step 2 with the next assertion of the story requirements.
Repeat with the next story.
Along the way, it's perfectly normal to have to define a new object or object member that never existed before, but which must now exist and function correctly. Here's where TDD starts paying you back, and where refactoring assistance like ReSharper pay for themselves several times over; simply code the test as if the code object you need already existed. This code obviously won't compile; that's your first goal, and ReSharper can fix pretty much all the red you'll see with a few presses of Alt+Enter. Once it compiles, the test still fails because the skeleton exists, but the logic still doesn't. Code that logic until the test passes, and then move on.

Hire Me For All Your Tutoring Needs
Integrity-first tutoring: clear explanations, guidance, and feedback.
Drop an Email at
drjack9650@gmail.com
Chat Now And Get Quote