C# TDD列表功能

C# TDD列表功能,c#,asp.net-mvc,tdd,C#,Asp.net Mvc,Tdd,我理解TDD的原理是首先编写一个测试,观察它失败(或者假设它将失败,因为还没有代码),编写一个方法,然后观察测试通过,因为它将使用您的新方法 如果您的方法返回boolean或integer或其他可用于以下任何一种的数据类型,我可以很明显地看到这是如何工作的: Assert.AreEqual(); Assert.IsNotNull(); Assert.IsTrue(); Assert.IsFalse(); etc. 但是,我构建的功能通常是返回某种类型列表的方法,如下所示: public sta

我理解TDD的原理是首先编写一个测试,观察它失败(或者假设它将失败,因为还没有代码),编写一个方法,然后观察测试通过,因为它将使用您的新方法

如果您的方法返回boolean或integer或其他可用于以下任何一种的数据类型,我可以很明显地看到这是如何工作的:

Assert.AreEqual();
Assert.IsNotNull();
Assert.IsTrue();
Assert.IsFalse();
etc.
但是,我构建的功能通常是返回某种类型列表的方法,如下所示:

public static List<Employee> GetEmployees()
{
  // return list of employees
}
公共静态列表GetEmployees()
{
//雇员申报表
}
我应该如何事先编写TDD测试(或者我的想法是错误的吗?)我显然是TDD新手(到目前为止,我还没有看到它的任何内在价值)。

使用。有很多集合断言。可以用于对象模拟

    private Mock<IActivityRepository> _mockActivityRepository;
    private Activity _expectedActivity = new Activity { Name = Name, Description = Details };

    /// <summary>
    /// Created by: kayz1
    /// Created: 23 jun 2011 23:48
    /// </summary>
    [Test, Description("GetAllActivities")]
    public void GetAllActivities_ValidProjects_ReturnProjects()
    {
        // Arrange
        var activities = new List<Activity> { _expectedActivity };
        _mockActivityRepository.Setup(x => x.GetAllActivities()).Returns(activities);
        // Act
        var resultList = _acitivityViewModel.GetAllActivities();
        // Assert
        _mockActivityRepository.VerifyAll();
        resultList.Should().HaveCount(1);
    }
private Mock\u mockActivityRepository;
私有活动_expectedActivity=新活动{Name=Name,Description=Details};
/// 
///创建人:kayz1
///创建日期:2011年6月23日23:48
/// 
[测试、描述(“GetAllActivities”)]
public void GetAllActivities\u ValidProjects\u ReturnProjects()
{
//安排
var活动=新列表{u expectedActivity};
_mockActivityRepository.Setup(x=>x.GetAllActivities())。返回(活动);
//表演
var resultList=_acitivityViewModel.GetAllActivities();
//断言
_mockActivityRepository.VerifyAll();
resultList.Should().HaveCount(1);
}

要断言集合,可以使用

通常,对于TDD函数,我想

  • 一个简单的快乐路径场景,比如只返回1个元素
  • 一个简单的异常场景,如不返回任何内容或抛出异常
  • 一个快乐路径,它将返回多个元素
  • 更复杂的路径将返回所有元素的筛选结果
  • 顺便说一句,如果您想使您的功能单元可测试,请避免静态或任何全局状态,或与I/O、数据库等通信(您可能希望模拟这些真实世界的对象)


    此外,如果所有外部函数状态都是通过参数而不是类字段传递的(不是静态的,也不是静态的),那么编写测试就更容易了。

    我们希望测试驱动此方法的开发(我正在删除静态):

    public List GetEmployees()
    {
    //雇员申报表
    }
    
    那么,我们能做的最低限度是什么

    public void ShouldReturnEmptyList() {
        List<Employee> list = new MyClass().GetEmployees();
        assertTrue(list.isEmpty());
    }
    
    public void ShouldReturnEmptyList(){
    List List=新建MyClass().GetEmployees();
    assertTrue(list.isEmpty());
    }
    
    好的,这很容易通过,对吗

    现在,让我们尝试填充列表:

    public void ShouldReturnListWithFred() {
        MyClass c = new MyClass();
        Employee fred = new Employee("fred");
        c.addEmployee(fred);
        List<Employee> list = c.GetEmployees();
        assertTrue(list.contains(fred));
    }
    
    public void应返回带有fred()的列表{
    MyClass c=新的MyClass();
    员工fred=新员工(“fred”);
    c、 增聘员工(弗雷德);
    List List=c.GetEmployees();
    assertTrue(list.contains(fred));
    }
    

    你差不多完成了。当然,您也可以探索例外情况,对排序等做出断言,但基本上这就是您测试列表返回方法开发的方式。

    要使TDD按预期工作,您需要从被测试单元的最简单方面开始

    你的第一个测试应该是:

    [TestMethod]
    public void GetEmployeesReturnsAList()
    {
        List<Employee> result = MyClass.GetEmployees();
        Assert.IsNotNull(result);
    }
    
    [TestMethod]
    public void GetEmployeesReturnsAList()
    {
    列表结果=MyClass.GetEmployees();
    Assert.IsNotNull(结果);
    }
    
    并这样实施:

    public static List<Employee> GetEmployees()
    {
      return new List<Employee>();
    }
    
    公共静态列表GetEmployees()
    {
    返回新列表();
    }
    
    现在,在添加代码以返回列表之前,此测试应该失败,从那时起,在所有重构和向测试单元添加代码的过程中,再也不会失败

    下一个测试类似于:

    //这个测试是错误的!!它缺少可用配置文件的设置 雇员

    我的意图是强调,返回1名员工是一个更简单的情况 而不是返回预期的特定员工。确保 从简单的例子开始

    //[TestMethod]//公共void GetEmployeesReturnsoneeEmployeewhen他们需要员工可用()//
    {//List result=MyClass.GetEmployees();//
    Assert.AreEqual(1,result.Count);/}

    //

    运行,测试失败。然后像这样重构:

    public static List<Employee> GetEmployees()
    {
        Employee emp = new Employee();
        List<Employee> empList = new List<Employee>();
        empList.Add(emp);
    
        return empList;
    }
    
    公共静态列表GetEmployees()
    {
    员工emp=新员工();
    List empList=新列表();
    雇主添加(emp);
    返回雇主;
    }
    
    现在测试通过了

    下一个测试可能是:

    [TestMethod]
    public void GetEmployeesReturns_The_OneEmployeeWhenThereIsOneEmployeeAvailable()
    {
        // Arrange
    
        Employee emp = new Employee();
    
        // Add code here to insert emp into the source of the list
        // This may be a mock.
    
        // Action
        List<Employee> result = MyClass.GetEmployees();
        Assert.AreEqual(1, result.Count);
        Assert.AreSame(emp, result[0]);
    }
    
    [TestMethod]
    public void GetEmployees返回一个Employeewhen他们需要员工可用()
    {
    //安排
    员工emp=新员工();
    //在此处添加代码以将emp插入列表的源中
    //这可能是一个嘲弄。
    //行动
    列表结果=MyClass.GetEmployees();
    Assert.AreEqual(1,result.Count);
    Assert.AreName(emp,结果[0]);
    }
    
    现在,您添加并重新编写代码,以使其通过,而不会破坏以前的任何单元测试

    冲洗并重复,添加尽可能少的代码以使测试通过,而不破坏任何其他测试。您将不得不多次重新编写代码,但结果是您得到了满足所有测试的最简单的代码。如果您的所有测试都完全代表了需求,那么您现在就拥有了一个功能齐全的单元

    TDD的关键在于,它可以防止不必要的复杂性,而这种复杂性通常是由于使代码变得比需要的更抽象或在发现需要复杂性之前产生的。当有需要时,您可以随时跟踪事实,使代码更加抽象。注意,合理的需求甚至可能是满足代码分析工具

    但是你可以自由地重新考虑,而不必担心,因为你有很好的测试覆盖率

    TDD的另一件事是,您可能希望使用技术边缘案例测试(传递空参数并测试适当的异常)来增强这些测试。然而
    [TestMethod]
    public void GetEmployeesReturns_The_OneEmployeeWhenThereIsOneEmployeeAvailable()
    {
        // Arrange
    
        Employee emp = new Employee();
    
        // Add code here to insert emp into the source of the list
        // This may be a mock.
    
        // Action
        List<Employee> result = MyClass.GetEmployees();
        Assert.AreEqual(1, result.Count);
        Assert.AreSame(emp, result[0]);
    }