我是否应该使用模拟以下示例

时间:2010-09-15 13:32:22

标签: c# unit-testing tdd mocking

我使用TDD相对较新,并且最近一直在阅读有关模拟对象的内容。我有以下测试来测试给定日期返回下一个星期六的方法。

[TestMethod()]
        public void NextSaturdayTest()
        {
            DateTime date = new DateTime(); 
            date = DateTime.Parse("2010-08-14");
            DateTime expected = new DateTime(); 
            expected = DateTime.Parse("2010-08-21");
            DateTime actual;
            actual = DateExtensions.NextSaturday(date);
            Assert.AreEqual(expected, actual);

            date = DateTime.Parse("2010-08-19");
            expected = DateTime.Parse("2010-08-21");
            actual = DateExtensions.NextSaturday(date);
            Assert.AreEqual(expected, actual);
        }

首先,这是否代表了良好的测试实践? 其次,利用模拟框架创建此测试的优势是什么?

如果我能提供更多信息,请告诉我。

感谢您的任何想法

4 个答案:

答案 0 :(得分:7)

首先,不要这样做:

DateTime date = new DateTime();
date = DateTime.Parse("2010-08-14");

您正在创建一个新的日期时间,然后在解析字符串以获取新的日期时将其丢弃。记住,测试代码应该仍然是好的代码。

其次,一个好的测试测试一件事。您可能会有多个测试,例如ReturnsCorrectNextSaturdayGivenAWednesdayReturnsCorrectNextSaturdayWhenCrossesEndOfMonthReturnsCorrectNextSaturdayWhenCrossesEndOfYear

最后,没有理由在这里嘲笑。如果您的DateExtensions调用另一个组件(比如数据库),并且您想伪造该调用,那么模拟将是合适的。因此,不是测试DateExtensions + Data Access,而是仅测试DateExtensions,当它调用数据访问层时,它将是您的测试设置的模拟。

答案 1 :(得分:5)

模拟用于满足依赖关系。

例如。考虑是否有一个使用IDataLayer(数据库周围的包装器)从数据库加载用户的类

public class UserService
{
    public UserService(IDataLayer layer) {}
    public User GetById(int id)
} 

测试时,您不希望针对数据库进行测试。这使得很难提供数据并检查结果。相反,您模拟IDataLayer对象以便能够手动向UserService提供用户。它使验证UserService完成它应该做的事情变得容易得多。

至于你的测试方法。我会把它分解为两种方法,因为你正在运行两种不同的测试(尽管使用相同的方法)

答案 2 :(得分:2)

在这种情况下,不需要使用模拟框架,因此不应使用。

您的测试相当合理。我个人将大部分日期解析内联为更好的可读性:

[TestMethod()]
    public void NextSaturdayTest()
    {
        DateTime actual = DateExtensions.NextSaturday(DateTime.Parse("2010-08-14"));
        Assert.AreEqual(DateTime.Parse("2010-08-21"), actual);

        actual = DateExtensions.NextSaturday(DateTime.Parse("2010-08-19"));
        Assert.AreEqual(DateTime.Parse("2010-08-21"), actual);
    }

答案 3 :(得分:2)

在这种情况下,我认为你没有嘲笑。通常你会模拟某种依赖(例如,如果你有一个DateProvider或者什么),但在这种情况下,直接使用DateTime对我来说很好。

但是,我会清理你的测试。你应该坚持每个方法测试一件事,因为如果那个测试方法失败了,你就会知道它为什么失败而不必检查断言并想知道其余的是否会通过。

[TestMethod()]
public void NextSaturdayReturnsCorrectValueStartingFromASaturday()
{
    DateTime date = DateTime.Parse("2010-08-14");

    DateTime expected = DateTime.Parse("2010-08-21");
    DateTime actual = DateExtensions.NextSaturday(date);

    Assert.AreEqual(expected, actual);
}

[TestMethod()]
public void NextSaturdayReturnsCorrectValueWithinTheSameWeek() 
{
    DateTime date = DateTime.Parse("2010-08-19");
    DateTime expected = DateTime.Parse("2010-08-21");
    DateTime actual = DateExtensions.NextSaturday(date);

    Assert.AreEqual(expected, actual);
}

正如其他人建议的那样,继续扩展您的测试类,以包括对您可能遇到的一些陌生情况的检查。