<file_sep>using System;
using TestingRandom;
using Xunit;

namespace TestingRandomTests
{
    public class DiceRollerTests
    {
        private DiceRoller _sut;

        public DiceRollerTests()
        {
            _sut = new DiceRoller(new Randomizer());
        }
        
        [Theory]
        [InlineData("fd6")]
        [InlineData("2df")]
        public void Roll_Throws_Format_Exception_For_Malformed_Input_String(string input)
        {
            void Act() => _sut.Roll(input);

            Assert.Throws<FormatException>(Act);
        }

        
        // TODO: Fix this test
        [Fact]
        public void Roll_Never_Out_Of_Range()
        {
            for (var i = 0; i < 100; i++)
            {
                var result = _sut.Roll("1d6");
                if (result < 1 || 6 < result)
                {
                    throw new Exception($"Result out of range: {result}");
                }
            }
        }
        
        // TODO: Figure out a way to test making sure the dice roller gets random numbers the right number of times
        // TODO: rolling "2d6" should call the randomizer twice, and pass in 6 to IRandomizer.Next(int)
    }
}
<file_sep>﻿namespace TestingRandom
{
    public interface IRandomizer
    {
        int Next(int maximum);
    }
}
<file_sep># Testing / Mocks Practice

I've got a `DiceRoller` class here that needs to be tested. I've got
a partial test suite started in *TestingRandomTests/DiceRollerTests.cs*, 
but it's got some problems. 

`DiceRoller.Roll(string)` accepts an input string formatted like a Dungeons
and Dragons dice roll. For example, *1d6* means roll a six-sided die one time, 
*2d8* means roll an eight-sided die twice, and so on.

## Task 

(1) `Roll_Never_Out_Of_Range` - Looping the action to test over and over
is a pretty bad way of testing Roll. Figure out a better way to test and 
make sure it's never out of range. 

(2) Figure out how to test making sure that the `DiceRoller` calls into
the `IRandomizer` the right number of times with the right argument.

Don't change `DiceRoller` to make this happen. You are not limited in the 
mocking technique / library you use.
<file_sep>﻿using System;

namespace TestingRandom
{
    public class DiceRoller
    {
        private readonly IRandomizer _randomizer;

        public DiceRoller(IRandomizer randomizer)
        {
            _randomizer = randomizer;
        }

        public int Roll(string diceExpression)
        {
            var expressionParts = diceExpression.Split('d');
            var dieCount = Convert.ToInt32(expressionParts[0]);
            var sideCount = Convert.ToInt32(expressionParts[1]);

            var sum = 0;
            
            for (var i = 0; i < dieCount; i++)
            {
                sum += _randomizer.Next(sideCount) + 1;
            }

            return sum;
        }
    }
}
<file_sep>﻿using System;

namespace TestingRandom
{
    public class Randomizer : IRandomizer
    {
        private readonly Random _random = new Random();
        
        public int Next(int maximum)
        {
            return _random.Next(maximum);
        }
    }
}
