Chess TDD 11: Tying Up Loose Ends
Now that all of the pieces are implemented, I decided to change it up a little and get rid of a few yellow items in one fell swoop. I thought it would also be a good time to
Here’s what I accomplish in this clip:
- Move Knight into it’s own class.
- Separated test and production into their own assemblies.
- Got rid of the DefaultBoardSize constant that had been defined in many test classes by consolidating it into one place.
- Went back to earlier test classes and implemented “MovesFromXX” pattern that I had settled on.
Here are some lessons to take away:
- If Ctrl-M, O stops working (or any normal VS shortcut), it might be because some other process has claimed part or all of the sequence and is preempting Studio. Kill processes or reboot.
- If you have some mundane but necessary tasks (e.g. moving a bunch of classes into a new namespace), this can be a good way to “warm up” when you haven’t looked at a code base in a while. Generally speaking, look for tasks that can ease you back into the code base while being productive.
- Even duplication that is seemingly mundane should be avoided. The DRY principle states that systems should have a single point of definition for all pieces of knowledge, and that includes things like database schemas, config files, and yes, even your unit test classes. You need to maintain your unit tests, and duplication creates maintenance pain.
- Pay attention to your test method names as you’re making changes. These are documentation as to how your code should behave, so if you change the behavior, make sure to change the names to reflect those changes.
- “Lean on the compiler” to help you with your refactorings. If you’re getting rid of a bunch of references to a variable, delete the definition of the variable and the compiler will then force you to get rid of all references. If you do it in the opposite order, you might miss references and waste time. As a more general rule, you should always favor failing early and doing things in such a way that mistakes will result in non-compiling.
- When you do large refactorings, it might not hurt to run all of the unit tests explicitly in the test runner instead of relying on the dots in NCrunch (or any continuous testing tool that you’re using).
[…] Chess TDD 11: Tying Up Loose Ends – Eric Dietrich continues his series looking at creating a Chess Game using Test Driven Development practices, following on from the implementation of the final pieces with some clean up and organisation […]
Yes! Another part! I could not wait for next part so I’ve started ahead and trying to be more TDD! Now I can enjoy seeing that I did some things right!
Question:
I’d like to to use 2 tests that are common for all pieces, e.g “GetMovesFrom.Returns_No_InvaliBoard_Coordinates_From_1_1” and “GetMovesFrom.Does_Not_Return_Starting_Position”
Is it possible to introduce a base test class of some kind? How will that work with the nested test class structure?
Certainly, it’s possible to have a test class for a base class — even an abstract one. Depending on your mocking framework, you can create a mock of the base that defaults to the defined method behavior for non-abstract members on the base class. Now, what you’re proposing is a little more complicated than that, though, since you want to express some kind of invariant that applies to all of inheritors (even those not yet defined). This is an interesting proposition, by the way. Here are two ways I can think to do it. First, you can use what I’m… Read more »
Ohh one more thing. The item on the list “Implement Equals on BoardCoordinate”.
Isn’t that unnecessary since structs that doesn’t contain reference type members does a byte-by-byte in-memory comparison as default Equals implementation? Or are you planning on using the == operator?
[…] ← Previous […]
Again great episode. I’m still really enjoying the format. I’m used to seeing a lot of ‘perfect’ screencasts, and I really like the view into your mind as well as the small pauzes and little errors. I noticed you do a lot of your refactorings using text manipulation. Did you consider making Boardcoordinate.DefaultBoardSize a property (which refers to Board.BoardSize), and then inlining the property? This is the sort of thing that saves a lot of manual text-manipulation (or search and replace). The same goes for movesFrom11, you could introduce a field (possibleMoves), remove the lines which sets the var, then… Read more »
If memory serves, I accidentally left the DefaultBoardSize in kind of a goofy state and went back later to refactor. With MovesFrom11 are you talking about replacing the field with a method that returns what I set that equal to? I suppose there’s no reason I couldn’t do that. One of the things I’ve tried to accomplish over the course of time is become fluent enough in various productivity tools that making changes of those natures is kind of an afterthought. As such, I don’t tend to give it a ton of thought until I notice it or someone brings… Read more »
I’ve just started going through the backlog of videos using Java instead of C# and at the end of this video, I had one failing test. Interestingly, it was due to my implementation of getMovesFrom() (specifically in the Pawn class) returning a List instead of a lazily-evaluated IEnumerable. My failing test was Does_Not_Return_2_4_When_Passed_2_2_If_Piece_Has_Already_Moved and it failed because MovesFrom22 was fully evaluated before setting Target.HasMoved = true. I guess my point is 1) it’s been an interesting experience translating from C# to Java and 2) that test seems a little fragile, since it depends on the order that the values are… Read more »
Been a good bit of time since looking at the specifics of this (and I’m a little short on time to delve back in the source control history now), but I’d certainly agree that element order mattering in a set is a no-no. Assuming that this was also true of the test I wrote in C#, that was certainly a test that could have been improved.