DaedTech

Stories about Software

By

Chess TDD 30: Starting To Be Idiomatic With SpecFlow

This episode went so poorly, I thought briefly about scrapping it and starting from scratch… but that would not be true to the premise I established at the outset where I’d do this unedited, flubs and all.  Having finished with the AsciiBoardBuilder, it was time to start putting Darren Cauthon’s ideas into play.  You can read up on that here.  I sized up what he had done and, in spite of knowing very little about SpecFlow, decided that I only needed certain parts of it for my purposes.  This turned out to be a mistake as something that I thought he had just added for illustrative/cosmetic purposes was decidedly non-cosmetic, and it took me a lot of floundering to figure that out.  Now, that’s not uncommon for me, per se — I’m a “figure it out by breaking it” sort of person, but it’s not exactly the stuff of scintillating videos.

Here’s what I accomplish in this clip:

  • Got the first idiomatic SpecFlow test written in the new feature.  Barely.  And ugly.

Here are some lessons to take away:

  • When using someone else’s example as a template for learning something you don’t yet know, don’t jump the gun and start tweaking and changing things before you get the example working.  Do as I say, not as I do.
  • No matter how long you’ve been doing this, you’ll still make off by one errors and get array bounds arithmetic wrong when it’s complicated.  Improve the odds in your favor by using TDD or, by some other mechanism that you come up with, if applicable.
  • When you find yourself writing a good bit of logic in test code (meaning, you’re writing a lot of code that you aren’t test-driving), ask yourself whether you could move the logic to production or find some other way to tease it out with TDD.  You can see by my floundering here that you become decidedly less productive when you’re writing a lot of code and just hoping for the best.
  • Using NCrunch, it’s pretty easy to run quick experiments to help with my debugging.  One such example was to start hard-coding the row/column indices to see for which ones exceptions were actually generated.
  • Similarly, putting a temporary precondition assert at the top of a test method to check your assumptions can also be a big help.  This is what started me down the path of realizing my mistake with the table’s header.  I finally sanity-checked my assumption that the table had 8 rows to find that it really only had 7.

By

ChessTDD 29: Finishing up the ASCII Board Builder

I actually recorded this episode right on the heels of the last one, so that I could keep a good rhythm with the ASCII builder class.  I finished that class up here.

Here’s what I accomplish in this clip:

  • Finished the class, as I mentioned.
  • Moved the class into the production code.

Here are some lessons to take away:

  • Sometimes you’ll write a test that goes red while writing the first line.  According to the strictest discipline, you should make that green and then keep going.  But if it’s a question of writing a few more characters or another line or something to get your fully realized red test into place, I, personally, think that’s okay.
  • If you’re going through your red-green-refactor cycle and, during the course of a refactoring, you introduce lines of code that none of the tests are hitting, be very careful.
  • If you’re in the middle of a refactoring and you start to wonder if maybe you aren’t changing the way the inputs and outputs could work, back out the refactoring work and get to a known, green state.
  • I’ve no doubt covered this before, but TDD is a great way to force yourself to think about how your API behaves with non-happy path inputs.  You’re writing tests that tease out implementation, rather than coding to get something working in a GUI.

By

ChessTDD 28: Preparing for Idiomatic SpecFlow

This week I’m starting the process of engaging more yak-shaving, but I think it’s important yak-shaving. If we’re going to be doing this SpecFlow thing in the series, let’s get it done right. In a post I made last week, Darren Cauthon took the time to put together this gist. I read through it and my eyes bugged out. That kind of visualization is solid gold for this problem space. How powerful is it to be able to show other developers (and hypothetical business stakeholders) these ASCII chess boards and say, “look, this movement works?!” So, I’m asking you to indulge me in the journey to get there.

Here’s what I accomplish in this clip:

  • Created AsciiBoardBuilder class to take strings like “BQ” and “WP” and turn them into pieces added to a Board instance.
  • Got half-ish way through implementing that class.

Here are some lessons to take away:

  • I created something called “AsciiBoardBuilder.”  There was a time when I would have immediately thought to have it implement an IBoardBuilder interface, but I’ve gravitated away from this over the years as it tends to lead to unnecessary abstraction at times.  We can always do this alter if we need some other means of constructing boards aside from just using the Board class itself.
  • In case you’ve forgotten, one trick I use is to create the production class in the same file as the test class at first, when convenient.  NCrunch runs a little quicker this way and you don’t have to flip back and forth between two files.  I leave it in here until it no longer makes sense to, usually (e.g. when some other production class needs to use my new class).
  • I did something that’s a little more complex than your average TDD scenario, wherein I was modifying two different production classes as I went.  This isn’t particularly common and you might not want to do it if you’re new to this or you run into trouble trying it.  But if it works for you, there’s no reason not to do this.
  • If you go look up a solution, such as how to implement a bit of Linq-fu, it’s probably worth writing an extra test or two that you expect to go green just to confirm that you really understand the behavior of the solution that you found.
  • What I did with factoring out GeneratedBoard may not be to your liking.  This has the upside of eliminating duplication but the downside of introducing a bit of indirection.  For me, the improvement in how succinct the test cases are is worth it, but you may not agree.  This isn’t always an exact science — taste does factor in.
  • I’m pretty rigid about strongly favoring one assert per test method.  Not everyone feels this way, but I felt it worth refactoring to assert only one thing: that the piece is a white bishop.  (As opposed to asserting that it’s white and then that it’s a bishop).  I suggest that unless there’s really no option but to have multiple asserts, you factor toward one.

By

ChessTDD 27: Parameterized Acceptance Tests and Scenarios

At this point, I’m not going to bother with excuses any longer and I’ll just apologize for the gaps in between these posts.  But, I will continue to stick with it, even if it takes a year; I rarely get to program in C# anymore, so it’s fun when I do.  In this episode, I got a bit more sophisticated in the use of SpecFlow and actually got the acceptance tests into what appears to be reasonable shape moving forward.  I’m drawing my knowledge of Specflow from this Pluralsight course.  It’s a big help.

Here’s what I accomplish in this clip:

  • Implemented a new SpecFlow feature.
  • Discovered that the different SpecFlow features can refer to the same C# class.
  • Implemented parameterized spec flow components and then scenarios.
  • Got rid of the “hello world-ish” feature that I had created to get up to speed in favor of one that’s a lot more useful.

Here are some lessons to take away:

  • When using new tools, you’re going to flounder a bit before the aha! moments.  That’s okay and it happens to everyone.
  • As your understanding of tooling and your environment evolves, be sure to evolve with it.  Don’t remain rigid.
  • Fight the urge to copy and paste.  It’s always a fight myself, but on the occasion that I don’t have a better solution right in the moment, getting a test green, than duplicating code, I force myself to feel the pain and re-type it.  This helps me remember I’m failing and that I need to make corrections.
  • When I got my bearings in SpecFlow and realized that I had things from the example that I didn’t actually need, I deleted them forthwith.  You can always add stuff back later, but don’t leave things you don’t need laying around.
  • Notice how much emphasis I placed throughout the clip on getting back to green as frequently as possible.  I could have parameterized everything wholesale in a broad refactoring, but I broke it up, checking for green as frequently as possible.
  • Sometimes sanity checks are necessary, especially when you don’t really know what you’re doing.  I was not clear on why 8 was succeeding, since I was querying for a piece off the board.  Just to make sure that I wasn’t messing up the setup and it was never even checking for 8, I added that exception in temporarily.  Use those types of checks to make sure you’re not tilting at windmills.  As I’ve said, getting red when you expect red is important.
  • No matter what you’re doing, always look to be refactoring and consolidating to keep your code tight.

By

ChessTDD 26: At Last, Acceptance Tests

Let’s get the excuses out of the way: busy, more work coming in, vacation, yada-yada.  Sorry for the delay since last time.  This episode is a short one just to get back on track.  I haven’t been writing much code lately in general, and I was already stumbling blindly through SpecFlow adpotion, so this was kind of just to get my sea legs back.  I wanted to get more than one acceptance test going and start to get a feel for how to divide the acceptance testing effort up among “features” going forward.

Here’s what I accomplish in this clip:

  • Cleaned up the dead code oops from last time.
  • Defined an actual feature file for spec flow, with four real acceptance tests.

Here are some lessons to take away:

  • I don’t really know how Specflow works very well, so that floundering around after pasting in the same text seemed to fix the problem is my way of avoiding programming by coincidence.
  • No matter what you’re doing (unit tests, production code, or, in this case, acceptance tests) you should always strive to keep your code as clean and conformant to the SRP as you can.
  • When you don’t know a tool, go extra slowly with things like rename operations and whatnot.  I’m referring to me changing the name of the spec flow files.  It’s easy to get off the rails when you don’t know what’s going on, so make sure you’re building and your tests are green frequently.