More TDD: Chipping Away

Over the past few days I have been using chunks of free time to figure out which tests to write next. In the last post, I was a little frustrated with the process, but almost immediately I found a groove and a style of writing tests that has been pretty productive. One of the biggest steps forward was to stop worrying about everything so much. The important thing is that I am trying, and I am moving forward. With that mental block out of the way, I got busy.

With setting up a shoe and dealing hands out of the way, I knew I needed a way to score the hands, so I built a test for a scoreHand function. Usually each test block, wrapped in an ‘it’, will have a couple of tests. Sometimes it will have more. They don’t start this way, I try to start each one with one test case, like this:

describe('scoreHand', function(){
    it('should check the dealerHand score', function(){
        assert.equal(scoreHand([5,5]), 10);
});

Eventually they grow larger. I try to encompass edge cases if I can think of them and both pass and fail cases where applicable. Currently, the scoreHand test is a medium sized test (for me) and it looks like this:

describe('scoreHand', function(){
    it('should check the dealerHand score', function(){
        assert.equal(scoreHand([5,5]), 10);
        assert.equal(scoreHand([10,8]), 18);
        assert.equal(scoreHand([3,5,8,2]), 18);
        var testHand = [6,5,10];
        assert.equal(scoreHand(testHand), 21);
    });
});

An example of a simpler test case is the very next test, testForBlackjack. I envision using this test just after the initial deal to determine if anyone has a blackjack. Simple function, simple test:

describe('testForBlackjack', function(){
    it('should check for 21', function(){
        assert.equal(testForBlackjack(scoreHand([10,11])), true);
        assert.equal(testForBlackjack(scoreHand([5,5])), false);
    })
});

Occasionally a test gets longer, and sometimes more complicated. I am learning to take this as a warning sign. It tells me that either I am trying to do too much with one test or too much with one function (or both). It can also start to feel brittle, too reliant on some not-quite-hashed-out syntax. A great example of that is my dealCard test and function:

describe('dealCard', function(){
    it('should deal one card to the correct player', function(){
        dealCard("player");
        assert.equal(playerHand.length, 3);
        assert.equal(shuffledShoe.length, 47);
        dealCard("player");
        assert.equal(playerHand.length, 4);
        assert.equal(shuffledShoe.length, 46);
        dealCard("dealer");
        assert.equal(dealerHand.length, 3);
        assert.equal(shuffledShoe.length, 45);
    })
});

I do not like the parameter I am passing, and I know I will have to rewrite the test when I clean up (redesign vs. refactor) the function. In fact, looking at the function again, I hate it even more. I will have to give that part of the code some attention soon.

Along the way, I did have an “ah-ha” moment with TDD, especially about the “Driven” part, so I made a little screencast about it for my YouTube channel. The video is up here, and I will talk about that in more detail in a later post, along with a neat bit of coding I learned thanks to WebStorm. As always, I try to keep my code up to date in my GitHub repositories, so if you want to look at the guts, blackjack is right here. Comments, questions and criticism welcome!

Advertisements

TDD part 3: Arrrrrrrrrrrrrrrrrrrrrgh

Testing is… not going perfectly. I’m not even sure it is going well. I can make the tests work. The asserts and whatnot are real, they check the right things, and they pass. But the format of my tests is starting to suck. I am sure this is due partially to my lack of familiarity with the testing syntax and partially to my lack of basic JavaScript knowledge, but that doesn’t make it any less frustrating.

This is what I mean by sucky syntax:

it('should have removed four cards from the shuffledShoe and dealt the right cards out', function(){
    var shuffledShoe = shuffleShoe(makeShoe(1));
    var card1 = shuffledShoe[0];
    var card2 = shuffledShoe[1];
    var card3 = shuffledShoe[2];
    var card4 = shuffledShoe[3];
    assert.equal(48, initialDeal(shuffledShoe).length);
    assert.equal(card1, playerHand[0]);
    assert.equal(card2, dealerHand[0]);
    assert.equal(card3, playerHand[1]);
    assert.equal(card4, dealerHand[1]);
});
it('should deal two cards each to the player and the dealer', function() {
    assert.equal(2, playerHand.length);
    assert.equal(2, dealerHand.length);
     //need to figure out this set of tests
 //
});

I want to do this right, I just haven’t been able to hack my way into right yet. I’ve tried assigning the variables outside the it block but in the describe block. I have tried a beforeEach block. I don’t know what to try next. I’ll keep trying though!

The other thing I struggle with is a question of granularity. Are my tests granular enough? Too granular? Should I be testing everything? I don’t know the answers to those questions either. One day I hope to be able to use this post as a kind of reminder of what it was be like to be honestly ignorant. To hopefully remember that, there really are very few stupid questions.

The nice thing is, my test results look like this:

Blackjack Game
 deck
 √ should exist 
 √ should have a length of 52 
 makeShoe
 √ should be a function 
 √ should have a length equal to deck*numberOfDecks 
 shuffleDeck
 √ should return a shuffledShoe the same length as the shoe 
 initialDeal
 √ should have removed four cards from the shuffledShoe and dealt the right cards out 
 √ should deal two cards each to the player and the dealer
 7 passing (14ms)

Intentionally Writing The Wrong Code

I decided to document the process of TDD with a short screencast that includes the first few steps of the TDD process. In the video, I write a failing test, write code that doesn’t pass, and then write “bad” code that makes the test pass. I’m hoping to demonstrate the principle, as I understand it, of writing the simplest code that makes a test pass. The last step in the video is writing an additional test that exposes the weakness of my simple code and will put me on the path to writing functional code. It’s just a few minutes long, but I suggest you watch in in HD (at least 720) and full screen, if you want to be able to read the code.

Test-Driven Development, part 2

Let me start off by saying, I’m new, I don’t know what I’m doing, and it is always possible I am a little wrong, a lot wrong, or even all the way wrong…

My understanding of Test-Driven Development is this: Start from scratch, write a failing test, run the test, write the simplest code that will make the test pass, write another test, etc. There is some nuance there that is hard to put into words but easier to put into practice. Usually your second failing test will require rewriting your simplest code from the first failing test into actual working code. Also, you want to keep writing tests about the same general thing until you are satisfied that thing is finished (or as finished as you need it for now). There will be some examples shortly.

I decided that I needed a very concrete and simple project to help me wrap my head around TDD. I have chosen to build the game of blackjack, with one player and the dealer. A fairly simple game with simple requirements. The dealer doesn’t even need “real” A.I. because the rules dictate the actions the dealer must take. If one is to think about how to go about playing a game of blackjack, it becomes very easy to list the steps in order. My list looks like this:

  1. Produce one or more decks of cards
  2. Combine those decks into a shoe of cards
  3. Shuffle the shoe
  4. Initial deal, 2 cards, player first
  5. Check for dealer blackjack
  6. Player input, check for bust
  7. Dealer takes cards as per the rules, check for bust
  8. Determine winner

For now I am not including betting. Point 6 breaks down into another list of choices like split and doubling down. But that’s the broad outline, and the order in which I think I am going to tackle the programming. So the first step is to have a deck. At this point I have no code at all, which means it is the perfect time to write my first test!

(I’m using mocha and node.js’s assert style. To get assert in there I added this line of code

var assert = require("assert");

)

The whole thing gets wrapped in a describe block, and then each logical separation gets a nested describe block too. Inside of those are the it blocks, the tests themselves:

describe('Blackjack Game', function(){
    describe('deck', function(){
        it('should exist', function(){
            assert.equal(typeof deck, 'object');
        });
    });
});

There it is. In the command line, I type “mocha”, hit enter and I get…

Blackjack Game
deck
1) should exist

1 failing

1) Blackjack Game deck should exist:
AssertionError: ‘undefined’ == ‘object’

Just the failing test I was looking for. I haven’t created deck, or anything else yet. Let’s fix that.

var deck = [];

Re-run the test, it passes!

Blackjack Game
deck
√ should exist

1 passing

That was simple, but that deck is empty, we wouldn’t play with an empty deck, would we? We need a deck that has 52 cards, let’s test that.

it('should have a length of 52', function(){
    assert.equal(deck.length, 52);
});

And of course, that test fails. Remember, failing is a good thing! So I filled the deck array up with 52 members. On some level it is probably important to know what those members are and to test against that as well, but I took the liberty of moving on. I can always come back once that is important.

In the same way, I wrote tests for the shoe and then built the shoe to make the tests pass. This image from my last post has the whole set of tests:

mocha

I lumped a set of three “subtests” into one test that checks that the decks add up to the right number of cards. I don’t know if that is the right way to do it, but it works well enough. Below is the totality of the blackjack code I have written so far. Not very impressive, but it all does exactly what I want it to do, for now. Next up is shuffling the shoe. I have to figure out how I am going to test that and then how I am going to actually shuffle. I copied a shuffling algorithm from a stack overflow post a few days ago that I know works, but I didn’t really understand how. I need to sit down with that for a while and see if I can make sense of it. I think the test I will have to compare, somehow, the starting shoe array against the shuffled shoe array. The details elude me, but I am working on it!

testedCode