views:

198

answers:

6

Let's say I'm starting to do a game with TDD. Is this a good first test?

[TestMethod]
public void Can_Start_And_End_Game()
{
    Tetris tetris = new Tetris();
    tetris.Start();
    tetris.End();
}

It basically forces me to define 3 things: the Tetris class and its Start() and End() methods, but besides that it's pretty useless. It might have its interest immediately as with them I can define that class and those methods, but later it probably won't serve any kind of purpose. Its only purpose would maybe show that it must be possible to start a game and end it without getting an exception in the middle.

What are your thoughts on that?

+1  A: 

I think that the purpose of the test can be made clearer by catching any exceptions and explicitly failing the test if it happpens:

[TestMethod]
public void Can_Start_And_End_Game()
{
    try
    {
        Tetris tetris = new Tetris();
        tetris.Start();
        tetris.End();
    }
    catch (Exception ex)
    {
        Assert.Fail("Unexpected exception thrown: " + ex.ToString());
    }
}
Fredrik Mörk
There's an `Assert.DoesNotThrow` method which does this.
strager
Isn't that redundant like saying "let x = x" or "if (true == true)"? I thought it was xunit convention that the "DoesNotThrow" idea is always implicit and understood, with or without Assertions of any kind, regardless of the name of the method.
apollodude217
+2  A: 

I'm not a big fan of this test. Yes it helped to define the interface, but it is not very strong for defining (and testing) behavior.

I think it might be better to have one test that handles the startup. It would probably assert the default settings or scoring values. Then I would have additional tests to see if you can end a game.

Ideally have each test method execute one behavior.

Jerod Houghtelling
+1. A good test has a single assertion in it; this one has none.
TrueWill
+1  A: 

Yes, the test confirms that no exception is thrown in the constructor, the Start() and the Stop() method.

I see little value in an a additional try/catch block within the test to catch exceptions. The tool executing the test will catch and report those. Using the principle TSTTCPW the test can do without the try/catch block.

You can make the test a little more meaningful by adding assertions at the end, for example validating the value of properties on the tetris object.

Please be aware of the difference between writing a unit test and using TDD. The value comes from understanding that difference.

John
+6  A: 

You're not really driving development of the Tetris class with this test - you've decided what its API should be, which is fine, but why not write a test that tests something it should actually be doing?

The tests should inform the API, not vice versa (imho).

Skilldrick
I think you nailed it. But also take a look at S. Lott's answer.
devoured elysium
@devoured - Thanks. I actually prefer S. Lott's :)
Skilldrick
+14  A: 

It basically forces me to define 3 things: the Tetris class and its Start() and End() methods,

True.

but besides that it's pretty useless.

False.

later it probably won't serve any kind of purpose

False, also.

Its ... purpose [is to] show that it must be possible to start a game and end it without getting an exception in the middle

And that's HUGE. Epic. Monumental.

Indeed, that test will fail so often that you'll grow to hate it. Every unhandled, uncaught exception from all kinds of random places in your program will fail this test. You'll build careful logging and debugging because of this test.

This test is EPIC.

S.Lott
Wow, I hadn't thought of that.
devoured elysium
EPIC!!!!!!!!!!!
strager
"This test is EPIC" +1 :)
Skilldrick
+1: Code always gets more complicated later.
WW
I always knew I was a programming genious. Now I have the proof.
devoured elysium
@devoured elysium: Sorry, you're not a genius. You're just following what the genius have told you to do. The good news is you're following geniuses.
S.Lott
+1  A: 

As S. Lott said, this test covers a TON of ground. It's so "worth it" that it's worth breaking up into at least 3 tests and adding appropriate assertions to each:

[TestMethod]
public void Test_Contructor()
{
    Tetris tetris = new Tetris();
    // make assertions
}

[TestMethod]
public void Test_Start()
{
    // setup
    Tetris tetris = new Tetris();

    // exercise
    tetris.Start();

    // make assertions
}

[TestMethod]
public void Test_End()
{
    // setup
    Tetris tetris = new Tetris();
    tetris.Start();

    // exercise
    tetris.End();

    // make assertions
}
apollodude217