单元测试的最佳实践

时间:2015-12-22 11:38:44

标签: c# unit-testing nunit

我想知道是否有单元测试(C#/ NUnit)的最佳实践来测试这样的解决方案: 想象一下,我在BLL(业务逻辑层)中有方法SELECT u.*, IFNULL(AVG(rating),0) as rating FROM user u LEFT JOIN rating r ON u.user_id = r.user_id GROUP BY r.user_id; ,它通过它的Id给我一个Order :)。所以我需要编写将使用硬编码func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { let image = self.arrayPhotos[indexPath.row].imagePhoto return image.size.height / UIScreen.mainScreen().scale } 参数调用此方法的测试,但例如GetOrderById(long orderId)如果没有具有此类id的记录,则测试将失败

Id

我需要一些解决方案来随时工作,创建临时记录可能吗?或者更好的解决方案..

任何想法?

3 个答案:

答案 0 :(得分:2)

  

所以我需要编写将使用硬编码的Id参数调用此方法的测试,但是例如var Id = 1;如果没有具有此ID的记录,则测试将失败

这表示您要么不编程接口,要么创建集成测试,而不是单元测试。很可能,它是两者的结合。

您的BLL应该只通过接口引用数据访问层(DAL)。它不应该有对实际类的硬编码引用。这些具体的类只应在运行时通过注射提供。因此,在测试时,您提供了一个模拟的DAL,当测试提供正确的Id工作时,它将具有带有特定Id的记录。同样,当测试BLL正确处理丢失的记录时,它将没有带有该Id的记录。

因为DAL被嘲笑,它完全处于测试的控制之下,因此很容易设置这些成功/失败条件。

答案 1 :(得分:2)

您没有提供有关此测试要达到的内容的详细信息。我想你想测试该方法是否能够从数据库中获取订单。正如David Arno所说,这是集成测试。通常,对数据库或文件系统的测试很糟糕,并且会进行缓慢而脆弱的测试。 如果您已使用接口将业务层与数据访问层分离,则可以使用Subsititue(在nUnit lib中)并将其提供给您的商务层。

Fx的:

IDataAccess interfaceStub = Substitute.For<IDataAccess>();

如果这还不够,就像我认为在这种情况下,您希望您的数据访问层返回对您的订单服务方法GetOrderById有用的内容。您可以创建数据访问层的“可测试版本”。

可能是这样的:

    //A few simple tests
    [TestMethod]
    public void CheckThatOrderExist()
    {
        var service = new OrderServiceTestable();
        var order = service.GetOrderById(1);//This will be found in the list
        Assert.IsNotNull(order);
    }

    [TestMethod]
    public void CheckThatOrderDoesNotExist()
    {
        var service = new OrderServiceTestable();
        var order = service.GetOrderById(2);//This will not be found
        Assert.IsNull(order);
    }

    //Your data access layer
    public class OrderService
    {
        protected virtual IList<Order> OrderList { get; set; }

        public Order GetOrderById(int id)
        {
            return OrderList.SingleOrDefault(x => x.Id == id);
        }
    }

    //Order object
    public class Order
    {
        public int Id { get; set; }
    }

    //This class inherits the order service and over write the list of orders. An instance of this class is used in the tests.
    public class OrderServiceTestable : OrderService
    {
        protected new List<Order> OrderList;

        public OrderServiceTestable()
        {
            OrderList = new List<Order> {new Order {Id = 1}}; //This will overwrite the list of orders because its virtual in the order service class
        }
    }

看看我做了什么?通过继承真正的类并覆盖虚拟的属性或方法。您可以使testable覆盖任何数据,同时您可以在OrderService类中测试实际方法。这将带来强大而快速的测试。您不测试数据访问层,而只测试业务层中的方法。但是,您可能需要做一些工作。

有了这个说法,我仍然建议与接口解耦。

答案 2 :(得分:0)

首先,您必须实现依赖性倒置原则,之后您将能够通过依赖注入使用MockObjects。