我想知道是否有单元测试(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
我需要一些解决方案来随时工作,创建临时记录可能吗?或者更好的解决方案..
任何想法?
答案 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。