Wrt: Rhino.Mocks, yes, I think a mocking tool is vital to a good TDD/BDD experience, and Rhino.Mocks has been great for me. YMMV.
-Steve
Steven Harman
- sent from my mobile phone
So I'm developing this console-app called "genTODO.exe" that's
supposed to scan a directory recursively (all .cs-files) and build a
HTML-report detailing all found "TODO-comments", eg.:
In MyClass.cs:
23: public void MyMethod() {
24: //
25: // TODO
26: //
27: }
In MySecondClass.cs:
143: ....
144: ...
...
Hopefully somewhat useful when it's done!
I have not finished the program yet, but so far this is what I've got:
Toplevel:
- Generator (depends on IFileLister, ISourceAnalyzer)
* IFileLister can list all files with a certain ending in a given
directory (also includes file in subdirectories)
* ISourceAnalyzer has one method to analyze a source file
Toplevel-1:
- FileLister (uses .NET API directly so it's an untested "boundary" class)
- SourceAnalyzer (depends on IReportBuilder, IFileLoader)
* IReportBuilder has one method to add a TODO-item (including
source file, "context" ie. the 5 files around the TODO)
* IFileLoader has a method to read the whole content of a file into
memory given it's path. It's an untested boundary class.
Hope that makes sense,
/Olof
Oh, and I should say where the DRY-break would come from:
1. The first user-story I've got is "No input file".
2. That should make Generator produce a "<html>No TODOs
found.</html>"-report via it's "string ProduceReport(path)"-method.
3. I believe this case will come up later on, eg. in the SourceAnalyzer-specs.
4. I've yet to reach that far down into the application to see if it
actually does.
Another concern I've had so far is "the top-level class gains
more-and-more-dependencies".
Let me explain. First of, I only had two dependencies in the Generator
class, namely IFileLister and IFileWriter. I thought "Well the input
is a path, and the output is a written file on disc, so this must be
the correct dependencies for the top-level class". Then, I found out
that the Generator needed to analyze actual text, and since that is
kind of the kernel in this application, I'd really like to use
BDD/TDD to "sculpture" that behaviour. So then I'd add another
ISourceAnalyzer dependency to the Generator class. Of course, the
SourceAnalyzer implementation would really like to talk to a
IReportBuilder instead of directly creating a partial HTML-file
(splitting responsibilities and all), so then Generator would need yet
ANOTHER dependency: IReportBuilder.
This confused the hell out of me. I thought "Is Generator supposed to
accumulate all this applications dependencies in it's constructor?".
Going even lower in the system, soon IGenerator would have to depend
on ALL interfaces of all sub-sub-sub class etc.
Then I found out, and this would be really interesting if you would
comment on, that Generator really only needed to have two dependencies
(as outlines in my previous post): IFileLister and ISourceAnalyzer. My
idea is that if ISourceAnalyzer needs a IReportBuilder to operate, it
is Generators responsibility to create such an object, but it is not
the USER of Generator that has to do it. So I'm "hiding" the creation
of the ReportBuilder inside the ProduceReport-method of Generator,
which initially seemed not-so-nice to me (breaking Michael Feathers
"avoid internal dependency"-rule after all..).
Any thoughts on this?
Cheers,
Greg
--
Studying for the Turing test
But this is an excercise on BDD, so I wanted to implement it myself.
2008/5/19 Greg Young <gregor...@gmail.com>:
http://unxutils.sourceforge.net/
http://gnuwin32.sourceforge.net/summary.html
But if this is just an exercise, then I applaud your effort.
Though I might suggest that perhaps you could experiment with BDD *AND*
produce something new to the community at the same time! :)
-c
-----Original Message-----
From: behaviordriv...@googlegroups.com
[mailto:behaviordriv...@googlegroups.com] On Behalf Of Olof
Bjarnason
Sent: Monday, May 19, 2008 3:22 PM
To: behaviordriv...@googlegroups.com
Subject: [BehaviourDrivenDevelopment] Re: Specs and the DRY principle
>
> But if this is just an exercise, then I applaud your effort.
The effort is really seeing through the "buzz" around BDD and getting
some non-religous details on how the method is used in practice. So
far, TDD has been a much better experience than BDD to me. With TDD I
got working from day one and improved my unit testing skills day by
day. I've been doing that for the past 2 years. It's been more than a
week of BDD-searching/groking now and I'm still not past this trivial
application.
Does anyone have any hands-on tutorials or walkthroughs, giving a
little more detail than "bdd is tdd done right"? Especially going into
the middle-to-low-levels of an application, not the
"story/account"-stuff that's duplicated 1000 times around the net.
How would any of you go about designing genTODO?
Thanks!
While that does deprecate the practical need for a 'genTODO.exe' in my
environment, it does not deprecate my need to learn BDD with something
of this level of complexity. So I will continue bugging you about my
progress, I'm sad to say :)
>
> >
>
> I wouldn't - it's built into Visual Studio 2002/3/5/8. Go to the View
> menu, click the "Task List" item, when that docked window shows up,
> change the list to "Comments" and it will show you all of your TODO's.
> WHen you double click on one, it will open the code file right to
> the //TODO comment.
+1 on that.
Olof, I commend and applaud your efforts to learn BDD, but I would very
politely and enthusiastically suggest to you that you spend your efforts
producing something that not only helps you learn BDD, but also helps
the community somehow.
Some ideas:
- Look at Scott Bellware's SpecUnit (googlecode) stuff for generating
HTML reports of specs based on test names and help him with that
- Maybe a tool that helps create a scaffold for BDD-style/named tests
where you can type in a AsA/When/Then scenario and it will generate a CS
file with the contexts/specs (fixtures/tests) stubbed out for you to
start writing tests (this may help do away with some of the
underscore-replacing-macros n'stuff)
-c
Nah, just a console app. I'm thinking of something like Rails' generate
app:
C:\>context<return>
Context:<prompt> selecting screens and products
When:<prompt> screen has been loaded with configured products <return>
Then:<prompt> should highlight selected product for screen<return>
Then:<prompt> should load screens for selected screens product<return>
Then:<prompt> should highlight loaded screens<return>
Then:<prompt> <return>
Generating 'selecting_screens_and_products.cs'...
You keep making comments like this...what do you see as the big
difference(s) between TDD and BDD?
Pat
Are you talking about NGem (which I haven't seen any progress lately on)
-----Original Message-----
From: behaviordriv...@googlegroups.com
[mailto:behaviordriv...@googlegroups.com] On Behalf Of Chad Myers
Sent: Wednesday, May 21, 2008 1:10 PM
To: behaviordriv...@googlegroups.com
Subject: [BehaviourDrivenDevelopment] Re: Specs and the DRY principle
-c
Well, I'm trying to learn BDD. I've done TDD for 2 years and I'm
generally satisified with that experience.
So far BDD seems to be
1) More "talkative"; you should not be afried of method names like
public void should_not_delete_original_files_on_user_cancel()
2) Top-down instead of bottom-up, resulting in lots of mocking and
dependency injection. That means that top-level code will look
something like:
ILister lister = new FileLister();
IWriter writer = new FileWrite();
Generator generator = new Generator(lister, writer);
generator.ProduceReport("c:\prj\ConsoleApp1", "c:\prj\ConsoleApp1TODO.html");
// Question: should the analyzer be injected too, or an internal
dependency (an implementation detail of generator)?
In TDD, I would have built some string-analyzing functionality first
of all, and the Generator class last. In BDD, I'm going the opposite
direction, starting with the generator and working my way into the
system. At least that's what I'm trying to do, but there's way too
many questions to finish this venture.
/Olof
>
> >
>
Okay, so this has been bugging me for a while.
BDD isn't about the technology. It isn't even about the code. It's
about the conversations you have with the business, and carrying the
language in which you have those conversations as far as you can.
For me, I start using the language when I talk to the business, then
carry it into the tests - after that we're still using DDD, but it's
out of BDD scope.
The reason we use phrases like "behaviour", "scenario" and "example"
are because they're words that our business and users understand. You
can't say "Give me an acceptance test." You can say "Define the spec",
if you like, but I find "Give me an example" or "Give me a scenario"
an even better way to talk about what software should do.
>> got working from day one and improved my unit testing skills day by
>> day. I've been doing that for the past 2 years. It's been more than a
>> week of BDD-searching/groking now and I'm still not past this trivial
>> application.
Anthony Bailey kindly typed up a conversation we had about what
experienced TDDers might get out of BDD. You may find it useful:
http://anthonybailey.livejournal.com/34156.html
>> Does anyone have any hands-on tutorials or walkthroughs, giving a
>> little more detail than "bdd is tdd done right"? Especially going into
>> the middle-to-low-levels of an application, not the
>> "story/account"-stuff that's duplicated 1000 times around the net.
1) Work out who the customer of your code is.
2) Find out from your customer how they want to use your code (don't guess).
3) Think of an example of the different contexts in which your
customer is going to use your code, and the different outcomes that
will result.
4) Write up enough examples to illustrate the desired behaviour.
They'll be of the form "Given, When, Then" (trust me, even if you use
a different language, all examples and scenarios have contexts (or
givens), events and outcomes).
5) The customer of your code may be some other piece of code. That
customer should already know how it's going to use your code - maybe
through an interface, which may be mocked out. If you find that you
need (or could usefully and responsibly use) some other pieces of
code, mock them out for now. If your customer is a real person (for
scenarios), your QA will be able to help you work out how your
customer will use your code, and what should happen.
6) When all the classes which are mocked have real classes that
correlate, and the scenarios (either automated or manual) that define
how your application should behave, behave, you're done. Next story.
There are also some ways of managing scope (either story or class
scope) using BDD, but these are the basics. Does it help?
> Stories a common part of various agile methodologies, not just BDD.
> BDD may have a specific format / syntax for them, compared to others
> though.
>
> I've got a post from a few months ago, that outlines my own journey
> from TDD unit testing to BDD unit testing, Hopefully this will help
> get you moving a little more.
>
> http://www.derickbailey.com/2008/03/09/MigratingAUnitTestFromTestDrivenDevelopmentToBehaviorDrivenDevelopment.aspx
Derick, I love the practicality with which you're designing scenarios.
I'm doing it C# at the moment. Here's a scenario:
GivenIAmNotLoggedIn();
WhenIOpenABrowserAt(HomePage);
ThenIShouldBeRedirectedTo(LoginPage);
WhenILogInAs("liz", "pa55word");
ThenIShouldBeRedirectedTo(HomePage);
We just put the steps in the method, and have one big "Scenario" class
that everything extends.
> For me, personally, BDD and the use of stories was like a light
> turning on in my head. For many, many months (around a year and a
> half), I struggled with the problem of starting with a blank screen
> and not knowing what to name the test fixture. When I started learning
> BDD from Scott Bellware, the problem that I had seen for so long
> suddenly began to go away.
Good. That's what we're hoping for. :)
Cheers,
Liz.
--
Elizabeth Keogh
l...@lunivore.com
l...@thoughtworks.com
http://jbehave.org
http://sirenian.livejournal.com
Are GivenIAmNotLoggedIn() and so on members of the Scenario class..?
So each specific scenario just has a "AcceptanceCriteria"-method or
something, where the above steps are coded?
If they're commonly used, they go in the Scenario class; otherwise
they stay in the specific scenario which needs them.
>>> We just put the steps in the method, and have one big "Scenario" class
>>> that everything extends.
>>
>> so you would have all those methods being called from one [Test]
>> method that is defined by your base Scenario class?
No; the base Scenario class has the definitions of the steps - it's
abstract, and just a template for running any particular scenario. The
subclasses have the defininition of the real, specific scenarios - so
the Given, When, Then above would appear in ICanLogin.cs, or something
similar.
It's a poor man's JBehave (for C#). :)
I can see at least one good reason to use this method: It is _very_
readable. What I've done so far in C#/NUnit, stretching NUnit and it's
dynamic mocks to its limits, is not at all this readable!
Thanks for bringing me "down to earth" with this :)
> I listened to Elizabeths advice on how to write acceptance criteria in
> C#, for example browse the HawkService story:
>
> http://code.google.com/p/csharphawkeye/source/browse/trunk/Hawkeye.Specs/HawkServiceStory.cs
>
> 1. I use NUnits TestFixture as "containers of acceptance criteria"
> 2. I use NUnits Test's as acceptance criteria
> 3. I use NUnits DynamicMock class to mock things
That's great! I hope you won't mind if I point people at this for an
example of how to do BDD without a framework...
Thanks :)
No problem, use C# Hawkeye as an example..
After reading the wiki BDD page, specifically the unit testing
example, I'm moving towards the use of "ExampleN" instead of "AC_N",
it feels even more natural:
[TestFixture]
public class ChangeTargetFolderStory {
[Test]
public void Example1() {
GivenUserPushesPickTargetFolder();
BrowsingBeginsInPreviousTargetFolder();
IfUserCancelsBrowse();
ShouldNotAlterTargetFolder();
}
[Test]
public void Example2() {
GivenUserPushesPickTargetFolder();
BrowsingBeginsInPreviousTargetFolder();
IfUserPicks("thisfolder");
ShouldSetTargetFolderTo("thisfolder");
}
}
I'm also leaning towards getting rid of [SetUp]/[TearDown]-methods,
since they are less readable than calling them from within the
example:
[TestFixture]
public class ChangeTargetFolderStory {
[SetUp]
public void BeforeEach() {
GivenUserPushesPickTargetFolder();
BrowsingBeginsInPreviousTargetFolder();
}
[Test]
public void Example1() {
IfUserCancelsBrowse();
ShouldNotAlterTargetFolder();
}
[Test]
public void Example2() {
IfUserPicks("thisfolder");
ShouldSetTargetFolderTo("thisfolder");
}
}
However, this is a judgement call to me, made on a story-by-story
basis.. The main rule is "readability" to me now, when it comes to
"checked examples". In production code, DRY is king.
Any opinions on this?
I still haven't decided on this issue. Here are some thought in my mind:
Con: Method names get huge => hard to read
Con: Example code is really easy to read
Con: Writing example code-lines feels more straight forward than
writing abstract method names to me
For example:
[Test]
public void IfUserCancels_TargetFolderIsKeptIntact()
{
GivenUserPushesPickTargetFolder();
BrowsingBeginsInPreviousTargetFolder();
IfUserCancelsBrowse();
ShouldNotAlterTargetFolder();
}
I guess a compromise would be to name it Example1() first, write down
the example lines, then coming up with a method name is one way to
have best of both worlds .. :)
However, it is arguably more readable.
2008/6/3 Jimmy Bogard <jimmy....@gmail.com>:
I'm on Visual C# 2008 express, I think macros are one of the things
that's missing from the standard editions, at least i can't find any
right now.
2008/6/3 Joe Ocampo <agil...@gmail.com>:
http://code.google.com/p/csharphawkeye/source/browse/trunk/Hawkeye.Specs/Story_HawkService.cs
/Olof
2008/7/19 Colin Jack <colin...@gmail.com>:
I've found very difficult the switch from API creator to system creator, but
I do see value in that approach. I'm not sure about the lack of low-level
tests for the reusable bits of your api, i still think tests can have two
audience: the business *and* the develoeprs using your code.
Seb
--------------------------------------------------
From: "Chad Myers" <ch...@chadmyers.com>
Sent: Sunday, July 20, 2008 7:58 AM
To: <behaviordriv...@googlegroups.com>