编译我的保龄球代码 kata 时出现单元测试 ArgumentOutOfRangeException

问题描述 投票:0回答:1
public class Game
{
    private IOutputProvider _outputProvider;
    private List<Frame> frames = new List<Frame>();
    private int currentRoll = 0;

    public Game(IOutputProvider outputProvider)
    {
        _outputProvider = outputProvider;

        for (int i = 0; i < 10; i++)
        {
            frames.Add(new Frame());
        }
    }

    public void StarteSpiel()
    {
        while (!Over())
        {
            _outputProvider.Write("Geben Sie die Anzahl der umgeworfenen Pins ein: ");

            string input = _outputProvider.Read();
            int pins;

            while (!int.TryParse(input, out pins) || pins < 0 || pins > 10)
            {
                _outputProvider.Write("Ungültige Eingabe! Bitte geben Sie eine Zahl zwischen 0 und 10 ein: ");
                input = _outputProvider.Read();
            }

            AddRoll(pins);
        }

        _outputProvider.Write("Spiel beendet! Endpunktzahl: " + TotalScore());
    }

    private void AddRoll(int pins)
    {
        if (Over())
        {
            throw new IndexOutOfRangeException("Das Spiel ist beendet!");
        }

        int frameIndex = GetCurrentFrameIndex();

        if (pins == 10 && currentRoll % 2 == 0 && frameIndex < 9)
        {
            _outputProvider.Write("Herzlichen Glückwunsch, Sie haben einen Strike geworfen!");

            frames[frameIndex].PinsRolled[0] = pins;
            frames[frameIndex].IsComplete = true;

            currentRoll += 2;
        }
        else
        {
            if (frames[frameIndex].PinsRolled[0] + pins > 10 && frameIndex < 9)
            {
                _outputProvider.Write("Die Summe der beiden Würfe in einem Frame darf nicht mehr als 10 betragen. Bitte geben Sie eine gültige Anzahl Pins ein: ");
                return;
            }

            // Den Wurf zum aktuellen Frame hinzufügen
            if (frames[frameIndex].PinsRolled[0] == 0)
            {
                frames[frameIndex].PinsRolled[0] = pins;
            }
            else
            {
                frames[frameIndex].PinsRolled[1] = pins;
                frames[frameIndex].IsComplete = true; // Frame ist vollständig
            }

            currentRoll++;
        }

        CalculateScores();
        _outputProvider.Write($"Aktuelle Punktzahl: {TotalScore()}");
    }

    private int GetCurrentFrameIndex()
    {
        return currentRoll / 2;
    }

    private int TotalScore()
    {
        int totalScore = 0;
        foreach (var frame in frames)
        {
            totalScore += frame.Score;
        }
        return totalScore;
    }

    private bool Over()
    {
        // Stelle sicher, dass das Spiel 10 Frames hat
        if (frames.Count < 10)
        {
            return false;
        }

        var lastFrame = frames[9];

        if (lastFrame.PinsRolled[0] == 10)
        {
            return lastFrame.PinsRolled.Length == 3 && currentRoll >= 12;
        }

        if (lastFrame.PinsRolled[0] + lastFrame.PinsRolled[1] == 10)
        {
            return currentRoll >= 11;
        }
        return currentRoll >= 20;
    }

    private void CalculateScores()
    {
        for (int i = 0; i < frames.Count; i++)
        {
            var frame = frames[i];

            if (frame.IsComplete)
            {
                if (IsStrike(i))
                {
                    CalculateStrikeScore(frame, i);
                }
                else if (IsSpare(i))
                {
                    CalculateSpareScore(frame, i);
                }
                else
                {
                    frame.Score = frame.PinsRolled[0] + frame.PinsRolled[1];
                }
            }
        }
    }

    private void CalculateStrikeScore(Frame frame, int frameIndex)
    {
        frame.Score = 10 + StrikeBonus(frameIndex);
    }

    private void CalculateSpareScore(Frame frame, int frameIndex)
    {
        frame.Score = 10 + SpareBonus(frameIndex);
    }

    private bool IsStrike(int frameIndex)
    {
        return frames[frameIndex].PinsRolled[0] == 10;
    }

    private bool IsSpare(int frameIndex)
    {
        return frames[frameIndex].PinsRolled[0] + frames[frameIndex].PinsRolled[1] == 10;
    }

    private int StrikeBonus(int frameIndex)
    {
        if (frameIndex + 1 < frames.Count)
        {
            var nextFrame = frames[frameIndex + 1];
            return nextFrame.PinsRolled[0] + (nextFrame.PinsRolled[1] != 0 ? nextFrame.PinsRolled[1] : (frameIndex + 2 < frames.Count ? frames[frameIndex + 2].PinsRolled[0] : 0));
        }
        return 0;
    }

    private int SpareBonus(int frameIndex)
    {
        if (frameIndex + 1 < frames.Count)
        {
            return frames[frameIndex + 1].PinsRolled[0];
        }
        return 0;
    }
}

所以大家正在写一个小游戏来计算我在保龄球比赛中打倒了多少瓶。我已经为基本上所有可能发生的情况编写了许多测试,但我无法修复我的测试在仅投掷罢工时失败的问题。

最终目标是生12窝,总分300分。我很困难,如果有人能帮助我那就太好了

这是我的框架类:

public class Frame
{
    public int[] PinsRolled { get; set; }
    public int Score { get; set; }
    public bool IsComplete { get; set; }

    public Frame()
    {
        PinsRolled = new int[2];
        IsComplete = false;
    }
}
c# unit-testing
1个回答
0
投票

错误发生在

if (frames[frameIndex].PinsRolled[0] + pins > 10 && frameIndex < 9)

因为

frameIndex
是 10,
frames.Count()
也是 10。由于索引从 0 开始,这意味着有效索引是 0、1、2、3、4、5、6、7、8、9,而不是 10。

摆脱索引越界问题的快速解决方案是

int frameIndex = GetCurrentFrameIndex();
if (frameIndex >= frames.Count()) {
    return;
}

结果可能会解决这个问题。但是,这将是一种解决方法,您应该更深入地了解为什么要尝试引用

frames
范围之外的框架。使用调试器修改
Over

© www.soinside.com 2019 - 2024. All rights reserved.