Question

Summary

I have written a RandomValues class which provide multiple methods to generate random values per value type. This static class shall be used later on as a tool for unit testing other project classes and whatsoever.

I did unit test each of the methods in a TDD manner.

Now, I see there could be some refactor to promote code reuse, which conducts me to ask this questions after having searched the Internet different kind of results. Among them, one keeps my attention.

Structuring Unit Tests

Aside, I really did like the idea of structuring the unit tests in a behavioural manner such as this:

Behavioral

Now, I wonder how to apply this to my case.

RandomValuesTests

[TestFixture]
public class RandomValuesTest {
    [Test]
    public void RandomInt_ReturnsRandomIntegerValues() {
        int unexpected = RandomValues.RandomInt();
        int actual = RandomValues.RandomInt();
        Assert.AreNotEqual(unexpected, actual);
    } 

    [Test]
    public void RandomInt_ReturnsInRangeIntegerValues() {
        int minValue = 12;
        int maxValue = 20;
        int actual = RandomValues.RandomInt(minValue, maxValue);
        Assert.IsTrue(minValue <= actual && actual <= maxValue);
    }

    [Test]
    public void RandomDateTime_ReturnsRandomDateTimeValues() {
        DateTime unexpected = RandomValues.RandomDateTime();
        DateTime actual = RandomValues.RandomDateTime();
        Assert.AreNotEqual(unexpected, actual);
    }

    [Test]
    public void RandomDateTime_ReturnsInRangeIntegerValues() {
        DateTime minValue = new DateTime(2000, 1, 1);
        DateTime maxValue = new DateTime(2000, 12, 31);
        DateTime actual = RandomValues.RandomDateTime(minValue, maxValue);
        Assert.IsTrue(minValue <= actual && actual <= maxValue);
    }

    [Test]
    public void RandomEnum_ReturnsRandomEnumValues() {
        RandomValuesEnum unexpected = RandomValues.RandomEnum<RandomValuesEnum>();
        RandomValuesEnum actual = RandomValues.RandomEnum<RandomValuesEnum>();
        Assert.AreNotEqual(unexpected, actual);
    }
}

RandomValues

public static class RandomValues {
    public static int RandomInt() { return RandomInt(int.MinValue, int.MAxValue); }
    public static int RandomInt(int minValue, int maxValue) {
        return generator.Next(minValue, maxValue);
    }

    // And the other Random[Type] here...

    private static Random generator = new Random();
}

Further thoughts

I have thought of organizing my tests using a base class which would provide two abstract methods: ReturnsRandomValues and ReturnsInRangeRandomValues, and make a test class per type overriding these two methods as follows.

RandomValuesTestBase<T>

public abstract class RandomValuesTestBase<T> where T : IComparable<T> {
    public abstract void ReturnsRandomValues();
    public abstract void ReturnsInRangeRandomValues(T minValue, T maxValue);
}

[TestFixture]
public class RandomInt : RandomValuesTestBase<int> {
    [Test]
    public override void ReturnsRandomValues() {
        // Use the same code as shown above for RandomInt_Returns...
    }

    [TestCase(10, 20)]
    public override void ReturnsInRangeRandomValues(int minValue, int maxValue) {
        // Use the same code as shown above for RandomInt_ReturnsInRange...
    }       

}

But then, I have to create a test class per type: bool, byte, char...

Built-In Types Table (C# Reference)

This doesn't sound good at all.

I'm now trying to figure out how I could start from the two references mentioned in the summary, and make a viable organization out of it.

Or else, I keep the old plain way of a single test file per class for this one...

Was it helpful?

Solution

I personally wouldn't worry about making your tests generic or abstract here. I think each type that your RandomValues class supports will require its own set of tests and might be implemented differently.

I think the important part is that the functionality of the RandomValues class is implemented using a test first approach. First you write your tests for random integers, then DateTimes, and so on. I think the tests you've written are simple, clean and easy to understand.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top