我应该提取一些单位测试代码吗?

时间:2013-06-16 14:28:43

标签: asp.net-mvc unit-testing c#-4.0 asp.net-mvc-4 tdd

我只是用mvc 4来研究tdd。

我有一个orderscontroller,它在构造函数中带有一个工作单元接口:

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

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

我对这个索引()进行了几次测试。

[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的爱!

1 个答案:

答案 0 :(得分: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);
    }
}