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.
For what it’s worth… the pain you are feeling is incredibly valuable. I’ve found that it makes me go one of two ways: I either move away from the painful tools, or I find ways to resolve the pain. With SpecFlow, years ago, I saw some real power with the Tables, but like you’ve noticed: They are very difficult to use. The code to iterate over them is exactly the type of code you don’t want in your tests. I ended up writing the SpecFlow.Assist namespace to convert those tables to objects and lists, which replaced the double-array index counting… Read more »
Oh, and one more thought, just in case this helps regarding the headers I put into the rows and columns: Regarding the table headers on top of the table, I believe it is Gherkin that requires them. This is off memory from years ago, but I believe it is/was expected that every table have a header row. It makes sense, as Gherkin was meant to make it easier to read and communicate, and header rows are better than none for that. Regarding the row headers on the left-side of the board… they are Darren’s convention. Chess does not operate with… Read more »
It just dawned on me that I have the 1-8 backwards in my gist. Haha, boy, I’m full of mistakes.
Good think I practice TDD, otherwise these types of mistakes would go straight to production. 🙂
A lot of what you mention in these comments is going to be the stuff of the next few episodes of this series. (I actually coded 31 yesterday before I’d published this one because I was annoyed with how 30 went). My rough plan is to get several tests working for the king, refactor the first feature I had, and then get serious about making the test code readable and succinct. That’s where a lot of the tips and thoughts you’re offering come in. It’ll either be finding packages that are already written or else factoring out common abstractions to… Read more »
That’s great! I’ll be waiting for the next posts, sounds good.