Qual è la prossima mossa logica TDD in questo esempio di apprendimento?

1

Mi sto facendo strada verso la scala TDD e sono arrivato a un punto in cui mi piacerebbe ricevere consigli sulla "prossima mossa". Mi rendo conto che potrebbe non esserci una sola risposta qui, quindi qualsiasi suggerimento logico sarebbe fantastico.

La cosa su cui penso di essere bloccata è sapere che tempo dovrei forzare la duplicazione o procedere con la funzionalità primaria implementata dal codice minimo (e temporaneo dovuto a non essere generale).

Sto provando ad andare in un rigoroso ciclo verde / rosso / ri-fattore. Inoltre, questo esempio è così semplice che non richiede alcun oggetto mocked, ma penso che sia ancora un esempio valido (correggimi se ho torto o sono entrato in una sorta di caso banale che non vale la pena lavorare con) .

UPDATE : ho continuato con questo quasi alla conclusione, quindi suppongo che lascerò perdere e vedere se qualcuno ha dei commenti e se no lo cancellerò ..

Test:

using NSpec;

namespace TicTacToe
{
    public class new_game : nspec
    {
        protected TicTacToeGame game;

        private void before_each()
        {
            game = new TicTacToeGame();
        }

        private void when_game_starts()
        {
            it["board should be clear"] = () => game.BoardState.should_be("---,---,---");
            it["it's x's turn"] = () => game.PlayerUp.should_be('x');
            it["no winner yet"] = () => game.Winner.should_be('-');
        }
    }

    public class specify_game : new_game
    {
        private void first_move()
        {
            context["is x in the center"] = () =>
                {
                    act = () => game.Move('x', 2, 2);

                    it["board should have x in the center"] = () => game.BoardState.should_be("---,-x-,---");
                    it["it's y's turn"] = () => game.PlayerUp.should_be('y');

                    context["then y in the center"] =
                        () =>
                            {
                                it["should throw OtherPlayerOccupiesSpaceException"] =
                                    expect<OtherPlayerOccupiesSpaceException>(() => game.Move('y', 2, 2));
                                it["no winner yet"] = () => game.Winner.should_be('-');
                            };

                    context["then y in the upper left"] = () =>
                        {
                            act = () => game.Move('y', 1, 1);
                            const string expectedBoardState = "y--,-x-,---";
                            it["correct board state is " + expectedBoardState] = () => game.BoardState.should_be(expectedBoardState);
                            it["it's x's turn"] = () => game.PlayerUp.should_be('x');
                            it["no winner yet"] = () => game.Winner.should_be('-');

                            context["then x in the middle top"] = () =>
                                {
                                    act = () => game.Move('x', 1, 2);
                                    const string expectedBoardState2 = "yx-,-x-,---";
                                    it["correct board state is " + expectedBoardState2] = () => game.BoardState.should_be(expectedBoardState2);
                                    it["no winner yet"] = () => game.Winner.should_be('-');

                                    context["then y in the right top"] = () =>
                                    {
                                        act = () => game.Move('y', 1, 3);
                                        const string expectedBoardState3 = "yxy,-x-,---";
                                        it["correct board state is " + expectedBoardState3] = () => game.BoardState.should_be(expectedBoardState3);
                                        it["no winner yet"] = () => game.Winner.should_be('-');

                                        context["then x in the middle bottom"] = () =>
                                            {
                                                act = () => game.Move('x', 3, 2);
                                                const string expectedBoardState4 = "yxy,-x-,-x-";
                                                it["correct board state is " + expectedBoardState4] = () => game.BoardState.should_be(expectedBoardState4);
                                                it["x wins"] = () => game.Winner.should_be('x');
                                            };
                                    };
                                };
                        };
                };
            context["is y int the center"] =
                () =>
                    {
                        it["should throw NotYourTurnException"] =
                            expect<NotYourTurnException>(() => game.Move('y', 2, 2));
                    };
        }
    }
}

Implementazione:

using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace TicTacToe
{
    public class TicTacToeGame
    {
        private readonly char[,] grid = new char[3,3];

        private bool xsTurn = true;

        public TicTacToeGame()
        {
            for (int i = 0; i < 3; i++)
            {
                for (int j = 0; j < 3; j++)
                {
                    grid[i, j] = '-';
                }
            }
        }

        public string BoardState
        {
            get
            {
                var sb = new StringBuilder();
                for (int i = 0; i < 3; i++)
                {
                    for (int j = 0; j < 3; j++)
                    {
                        sb.Append(grid[i, j]);
                    }
                    if (i < 2)
                        sb.Append(',');
                }
                return sb.ToString();
            }
        }

        public char PlayerUp
        {
            get { return xsTurn ? 'x' : 'y'; }
        }

        public void Move(char player, int down, int over)
        {
            over -= 1;
            down -= 1;
            if (player != PlayerUp)
                throw new NotYourTurnException();
            if (grid[down, over] != '-')
                throw new OtherPlayerOccupiesSpaceException();
            this.grid[down, over] = player;
            xsTurn = !xsTurn;
        }

        public char Winner
        {
            get
            {
                string boardState = BoardState;

                var xWins = new[]
                    {
                        "xxx,...,...",
                        "...,xxx,...",
                        "...,...,xxx",
                        "x..,x..,x..",
                        ".x.,.x.,.x.",
                        "x..,x..,x..",
                        "..x,..x,..x",
                        "x..,.x.,..x",
                        "..x,.x.,x..",
                    };

                    var yWins = new[]
                    {
                        "yyy,...,...",
                        "...,yyy,...",
                        "...,...,yyy",
                        "y..,y..,y..",
                        ".y.,.y.,.y.",
                        "y..,y..,y..",
                        "..y,..y,..y",
                        "y..,.y.,..y",
                        "..y,.y.,y..",
                    };

                if (xWins.Any(win => Regex.IsMatch(boardState, win)))
                    return 'x';

                if (yWins.Any(win => Regex.IsMatch(boardState, win)))
                    return 'y';

                return '-';
            }
        }
    }
}

Output:

PM> NSpecRunner.exe .\TicTacToe\bin\Debug\TicTacToe.dll

new game
  when game starts
    board should be clear
    it's x's turn
    no winner yet
  specify game
    first move
      is x in the center
        board should have x in the center
        it's y's turn
        then y in the center
          should throw OtherPlayerOccupiesSpaceException
          no winner yet
        then y in the upper left
          correct board state is y--,-x-,---
          it's x's turn
          no winner yet
          then x in the middle top
            correct board state is yx-,-x-,---
            no winner yet
            then y in the right top
              correct board state is yxy,-x-,---
              no winner yet
              then x in the middle bottom
                correct board state is yxy,-x-,-x-
                x wins
      is y int the center
        should throw NotYourTurnException

17 Examples, 0 Failed, 0 Pending
    
posta Aaron Anodide 18.03.2013 - 23:06
fonte

1 risposta

1

Per rispondere ai commenti che hai ricevuto, penso che questo sia stato un esperimento utile.

Per rispondere alla tua domanda, l'approccio che faccio è di fare la cosa più semplice per far passare il test. Questo può avere uno dei due risultati.

Il primo risultato è che è necessario un altro test. Questo succede quando il codice che hai scritto non può essere abbastanza buono. L'esempio che uso sempre per dimostrarlo è un metodo che aggiunge due numeri.

Prova:

expect(plus(2, 2)).to eq(4)

Implementazione:

def plus(x, y)
  return 4
end

Questo è il modo più semplice per passare il test, ma ovviamente non è abbastanza buono. Quindi dobbiamo aggiungere un altro test in modo che, affinché entrambi i test possano passare, l'implementazione deve essere corretta.

Prova:

expect(plus(2, 2)).to eq(4)
expect(plus(2, 3)).to eq(5)

Implementazione:

def plus(x, y)
  return x + y
end

Il secondo risultato è che finisco per copiare e incollare, perché questo è il modo più semplice per ottenere una barra verde. Ma questo mi lascia con una duplicazione che non voglio. Quindi refactoring in piccoli pezzi per rimuovere qualsiasi duplicazione e mantenere la barra verde mentre vado. Non riesco a pensare a un buon piccolo esempio per dimostrarlo, il che è qualcosa su cui dovrei lavorare.

    
risposta data 12.06.2013 - 05:13
fonte

Leggi altre domande sui tag