C# 组织单元测试:班级还是行为?从哪里开始?

C# 组织单元测试:班级还是行为?从哪里开始?,c#,unit-testing,organization,code-organization,C#,Unit Testing,Organization,Code Organization,摘要 我编写了一个RandomValues类,它提供了多种方法来生成每种值类型的随机值。该静态类应稍后用作单元测试其他项目类的工具 我以TDD的方式对每个方法进行了单元测试 现在,我看到可能会有一些重构来促进代码重用,这让我在搜索了互联网上不同类型的结果后提出了这个问题。其中,有一个保持着我的注意力 除此之外,我真的很喜欢以如下行为方式构建单元测试: 现在,我想知道如何将此应用到我的案例中 RandomValuesTests 进一步思考 我曾想过使用一个基类来组织我的测试,该基类将提供两个抽

摘要

我编写了一个
RandomValues
类,它提供了多种方法来生成每种值类型的随机值。该静态类应稍后用作单元测试其他项目类的工具

我以TDD的方式对每个方法进行了单元测试

现在,我看到可能会有一些重构来促进代码重用,这让我在搜索了互联网上不同类型的结果后提出了这个问题。其中,有一个保持着我的注意力

除此之外,我真的很喜欢以如下行为方式构建单元测试:

现在,我想知道如何将此应用到我的案例中

RandomValuesTests

进一步思考

我曾想过使用一个基类来组织我的测试,该基类将提供两个抽象方法:
ReturnsRandomValues
returnsinrangerangerandomvalues
,并按类型创建一个测试类,覆盖这两个方法,如下所示

RandomValuesTestBase

公共抽象类RandomValuesTestBase其中T:IComparable{
公共摘要void ReturnsRandomValues();
公共抽象void返回sinRangeRandomValues(T最小值,T最大值);
}
[测试夹具]
公共类RandomInt:RandomValuesTestBase{
[测试]
public override void ReturnsRandomValues(){
//对RandomInt_返回使用如上所示的相同代码。。。
}
[测试用例(10,20)]
公共重写void ReturnsInRangeRandomValues(int-minValue,int-maxValue){
//对RandomInt_ReturnsInRange使用如上所示的相同代码。。。
}       
}

但是,我必须为每个类型创建一个测试类:
bool
byte
char

这听起来一点也不好

我现在正试图找出如何从总结中提到的两个参考文献开始,并从中创建一个可行的组织


或者,我保留了以前的简单方式,即在这个类中每个类都有一个测试文件…

我个人不会担心在这里让您的测试变得通用或抽象。我认为,
RandomValues
类支持的每种类型都需要自己的测试集,并且可能会以不同的方式实现


我认为重要的部分是,
RandomValues
类的功能是使用测试优先的方法实现的。首先编写随机整数的测试,然后编写日期时间,依此类推。我认为你所写的测试简单、清晰、易懂。

+1并接受了你的答案,因为你完美地回答了我的问题。除此之外,我想知道一个更复杂的情况是最佳实践方面的最佳做法。
[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);
    }
}
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();
}
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...
    }