1

我只是在用 mvc 4 研究 tdd。

我有一个订单控制器,它在其构造函数中采用一个工作单元接口:

public OrdersController(IUnitOfWork db)
{
this.db = db;           
}

//
// GET: /Orders/
public ActionResult Index()
{                      
    return View(db.Orders.GetAll());
}

我对此 Index() 进行了一些测试。

[TestClass]
    public class when_the_order_controller_index_action_executes
    {
        [TestMethod]
        public void it_should_render_the_default_view()
        {
            var uow = new Mock<IUnitOfWork>();
            var db = uow.Object;

            var orders = new List<Order>()
            {
                new Order{CreatedDate = DateTime.Now.AddMonths( -3),OrderID = Guid.NewGuid()},
                new Order{CreatedDate = DateTime.Now,OrderID = Guid.NewGuid()}
            };

            uow.Setup(r => r.Orders.GetAll())
                .Returns(orders);

            //arrange
            var controller = new OrdersController(db);

            //act
            var result = controller.Index() as ViewResult;

            //assert
            Assert.AreEqual("", result.ViewName);
        }

        [TestMethod]
        public void it_should_pass_orders_as_the_model()
        {
             var uow = new Mock<IUnitOfWork>();
            var db = uow.Object;

            var orders = new List<Order>()
            {
                new Order{CreatedDate = DateTime.Now.AddMonths( -3),OrderID = Guid.NewGuid()},
                new Order{CreatedDate = DateTime.Now,OrderID = Guid.NewGuid()}
            };


            uow.Setup(r => r.Orders.GetAll())
                .Returns(orders);

            //arrange
            var controller = new OrdersController(db);

            //act
            var model = ((ViewResult)controller.Index()).ViewData.Model as IEnumerable<Order>;

            //assert
            Assert.IsTrue(orders.Equals(model));
        }
    }

您会注意到在用于创建 GetAll 可以返回的列表的两个测试中存在大量代码重复...

说一个可重用的函数来返回两个测试都可以调用的列表是好还是坏的做法?

对我编写的测试的任何一般性建议也将不胜感激,因为我现在才接受 tdd 的爱!

4

1 回答 1

3

[TestInitialize]是的,在单元测试的一个阶段重构所有常见的代码初始化通常被认为是一种很好的做法。您还可以将您感觉非常重复的单元测试的所有常见初始化/断言部分外部化为可重用方法。

因此,在您的特定示例中:

[TestClass]
public class when_the_order_controller_index_action_executes
{
    private IUnitOfWork db;
    private OrdersController sut;

    [TestInitialize]
    public void TestInitialize()
    {
        var uow = new Mock<IUnitOfWork>();
        this.db = uow.Object;

        var orders = new List<Order>()
        {
            new Order{ CreatedDate = DateTime.Now.AddMonths(-3),OrderID = Guid.NewGuid() },
            new Order{ CreatedDate = DateTime.Now,OrderID = Guid.NewGuid() }
        };

        uow.Setup(r => r.Orders.GetAll()).Returns(orders);

        this.sut = new OrdersController(db);
    }

    [TestMethod]
    public void it_should_render_the_default_view()
    {
        //act
        var result = this.sut.Index() as ViewResult;

        //assert
        Assert.AreEqual("", result.ViewName);
    }

    [TestMethod]
    public void it_should_pass_orders_as_the_model()
    {
        //act
        var model = ((ViewResult)this.sut.Index()).ViewData.Model as IEnumerable<Order>;

        //assert
        Assert.IsTrue(orders.Equals(model));
    }
}

但通常这是每个单元测试阶段的uow.Setup(r => r.Orders.GetAll()).Returns(orders);一部分,因为它不同。//arrange这是您定义期望的地方。在您的特定示例中,我还将两个测试合并为一个:

[TestClass]
public class when_the_order_controller_index_action_executes
{
    private IUnitOfWork db;
    private OrdersController sut;

    [TestInitialize]
    public void TestInitialize()
    {
        var uow = new Mock<IUnitOfWork>();
        this.db = uow.Object;

        var orders = new List<Order>()
        {
            new Order{ CreatedDate = DateTime.Now.AddMonths(-3),OrderID = Guid.NewGuid() },
            new Order{ CreatedDate = DateTime.Now,OrderID = Guid.NewGuid() }
        };

        uow.Setup(r => r.Orders.GetAll()).Returns(orders);

        this.sut = new OrdersController(db);
    }

    [TestMethod]
    public void it_should_render_the_default_view_and_pass_the_expected_view_model_to_it()
    {
        //act
        var actual = this.sut.Index();

        //assert
        Assert.IsInstanceOfType(actual, typeof(ViewModel));
        var viewResult = (ViewResult)actual;
        Assert.AreEqual(model, viewResult.Model);
    }
}
于 2013-06-16T14:39:09.080 回答