views:

133

answers:

6

I have this first integration test for a tic tac toe game:

[TestClass]
public class FirstIntegrationTest
{
    [TestMethod, TestCategory("Integration Tests")]
    public void Standard_TicTacToe_Game_PlayerO_Wins()
    {
        IPlayer playerO = new Player();
        IPlayer playerX = new Player();

        Game game = new Game(playerO, playerX);
        game.Start();

        playerO.Play(new Point(0, 0));
        playerX.Play(new Point(2, 2));
        playerO.Play(new Point(1, 0));
        playerX.Play(new Point(1, 2));
        playerO.Play(new Point(2, 0));

        Assert.IsTrue(game.IsOver);
        Assert.IsTrue(playerO.HasWon);
        Assert.IsFalse(playerX.HasWon);
    }
}

Later I will add at least another one that takes care of showing up on to the User the board of the game. For the current one, I am only interested in what is shown above.

When doing integration tests (and this is an integration test, I suppose?) what kind of Unit-Tests should I do? Should I just make the minimum just to make the Integration Test pass? If that is so, I'd only need to make the Game class set its first IPlayer HasWon to true and the second one to false. What would be the point of Unit-Testing at all if I'm driving my design by the integration tests?

I have the idea that generally you don't have a lot of integration tests. So, should I be driving my design by Integration-Tests or by Unit-Tests?

+2  A: 

I'd not call it integration test, to me it's more like a Build Verification Test. A short and basic test that you run after a build to test, if the components fit together. A test that touches each module. So you test if you can create players, create a game and play a scripted game.

An Integration test would contain more tests concerning the interfaces between modules (csci).

Unit tests are below BAT and Integration test. They assure that at least all public methods in your compilation units work as expected and handle wrong input correctly.

So yes, you'll have a lot of more methods covered by unit tests.

Example for a unit test of the constructor of the Game class:

   IPlayer playerO = new Player();
   IPlayer player1 = new Player();
   IPlayer player2 = new AnotherImplOfIPlayer();

   Game game0 = new Game(player0, player1);   // this should work
   Game game1 = new Game(player0, player2);   // this should work
   Game game2 = new Game(null, null);         // exception thrown?    
   Game game3 = new Game(player0, player0);   // exception thrown?

A unit test verifies that the compilation unit is correct. You've put some requirements on the compilation unit (written or kept in mind) and verify those requirements. Totally independent from functionality of the higher application. Why? Because you may want to reuse the compilation unit in other projects and want to be sure that this compilation unit is error free (regarding the unit specs).

A BVT verifies, if the build process was correct and complete. It verifies if it produced an executable application.

A function test targets the functional requirements for the full application. A lot of functional tests are not automatic but done with written test scripts and executed by testers.

Andreas_D
Ok, seems like this is really what people call functional/acceptance tests. But what will drive the design of the game? Should I make just enough so that this functional test passes? Do I even need Unit-Tests to make this test pass?
devoured elysium
@devoured elysium: http://xkcd.com/221/
Merlyn Morgan-Graham
+1  A: 

I think this is good as an integration test, and you will need unit tests for specific behaviour of exposed public methods, i.e. what if a Player plays same movement twice? Who is responsible for this not to happen?

public void cannotPlaySameMovementTwice() {
    playerO.Play(new Point(0, 0));
    playerX.Play(new Point(0, 0));
    // You should assert some exception result here
}
hhbarriuso
So, if I got you right, doing Integration(or functional or wtv) tests when doing TDD-Style is just like a "guide" to know the overal design of the system, being that a lot of the details (probably most) aren't covered by Integration/functional tests but by Unit-tests. Is this right?
devoured elysium
Integration tests allow you to integrate components of your system (Game and Players). Unit tests allow you to test specific behaviour of your components isolated from other components.
hhbarriuso
+1  A: 

algorithms are always the hardest to test, because to be truly sure it works, you have to test every possible combination of everything. Realistically, its up to you to decide where to draw the line.

What you have here is a high level acceptance test.

possible unit tests are:

  • ensure players can only take turns alternately
  • ensure players can't both mark a coordiate
  • ensure wins in veritcal, diagonal and horizonal are recognised (could test all 8 possibilities here)
Andrew Bullock
@Andrew Bullock, devoured elysium: `to be truly sure it works, you have to test every possible combination`. I understand there are tools to help you figure out logically you *have* to test, vs what is redundant and overkill. The technique is called pairwise testing. I am not sure if this is a good link or not, but it was a high google hit: http://www.pairwise.org/
Merlyn Morgan-Graham
+1  A: 

The problem with answering your question is that it is subjective, and we don't know your app like you do.

For a general answer, I'd go utilitarian. Do whatever gets your app coded fastest, most bug free, and most maintainable. The unit tests count as far as all these go, as well.

If you find it easier to write and understand integration tests or end to end tests, write those. If you think you'll have to maintain them less, then that's the way to go.

If you find it easier to test every nook and cranny by focusing on unit tests, do that. If you can write them in a maintainable manner, then that will work well.

In my experience, unit tests are shorter to write, and can dig deeper with less effort. That is why I prefer them. I write fewer integration tests (tests that that cover major paths, and I tend to use them as BVTs), and even fewer "end-to-end" tests (if I have multiple applications/server client pairs, full processes etc to test).

Merlyn Morgan-Graham
A: 

In TDD, each test should cause you to create or change one thing in your code, which generally speaking means unit tests.

This particular test can't pass until you've created an interface, three classes and at least four methods. So I wouldn't call it test-driving.

Don Roby
It's not clear to me what you mean by not "test-driving". Do you mean its not test-driving the design?
devoured elysium
Right. It's not TDD.
Don Roby
In "Growing Object Oriented Software, Guided by Tests" this is just what the guys did. And they do TDD. They call this "creating the Walking Skeleton"
devoured elysium
+1  A: 

The difference between a unit test and integration test is very subjective.

Some would say that it's an integration test when you're combining more than one unit (as you are here). Others would say that it needs to touch some component outside of your control in the environment (such as a database or external API) in order to be an integration test.

Though I tend to prefer the latter definition, the argument could be made for each. And even then, does it really matter in reality? It's a useful test, it's fast, and it's more stable than an integration test. For this reason, I'd group it with unit tests in my local and CI testing.

At a push you could call this an acceptance test, though it's very much grey box and not really written in the users terminology.

Usually your system would be much bigger than your tic-tac-toe game and the distinction between unit, integration and acceptance testing would be clearer - giving you the scope to test at all three levels of abstraction.