【问题标题】:How to unit test a method or constructor which creates a new instance of another class如何对创建另一个类的新实例的方法或构造函数进行单元测试
【发布时间】:2015-04-20 17:48:21
【问题描述】:

我已经对这个主题进行了广泛的研究,但还没有找到可靠的答案,所以就到这里吧。

我有一个要测试的构造函数。这个构造函数初始化另一个类,以便设置一个全局变量,这在整个类的其余部分都是必需的。但是,构造函数初始化的类的构造函数依赖于 Web 会话和其他设置的变量,这些变量在任何测试运行时都没有设置。我怎样才能正确地模拟它以确保我只是在测试构造函数?

这里是要测试的构造函数:

public CheckoutManager()
{
    _orderController = new OrderController();
    _orderController.PropertyChanged += (sender, args) => NotifyPropertyChanged(args.PropertyName);
}

问题出在 OrderController 构造函数上:

public OrderController()
{
    _customer = WebUserSession.Current.Profile.Customer;
    _srd = ContextManager.GetStandardRequestByCulture( CultureInfo.CurrentUICulture.Name );
    WarehouseData data = new WarehouseData();
    data.WarehouseID = 0;   // TODO: Convert the 0 warehouse to a web warehouse type

    // Grab the attention items from the session
    AttentionItems = WebUserSession.Current.OrderAttentionItems;

    // Load the shopping cart
    _cart = ShoppingCartManager.Cart;
}

这是我尝试的测试:

[TestMethod]
public void Constructor_ExpectInstantiation()
{
    var checkoutManager = new CheckoutManager();

    Assert.IsNotNull( checkoutManager );
}

它在 _customer = WebUserSession.Current.Profile.Customer 处爆炸;线。你如何使用 Moq 模拟这个?如果它不能被嘲笑,有没有很好的解释为什么?如何以更可测试的方式修改原始构造函数以具有相同的功能?提前谢谢你。

【问题讨论】:

  • 考虑注入你不能在构造函数中模拟的静态依赖项
  • 您可以在测试框架中使用 [TestInitialize] 函数来设置测试运行。您是在问如何制作网络会话和其他东西,还是只是在测试前如何初始化一些东西?

标签: c# unit-testing constructor moq


【解决方案1】:

您可以使用Dependency InjectionInversion of Control 的一种形式)来解决此类问题。

不要在构造函数中实例化您的OrderController,而是将其作为参数传递:

public CheckoutManager(OrderController orderController)
{
    _orderController = orderController;
    _orderController.PropertyChanged += (sender, args) => NotifyPropertyChanged(args.PropertyName);
}

然后,您可以在类似Main 的方法中手动实例化OrderController,或者使用类似Autofac 的库来为您完成所有连接。

所以现在你可以在测试中模拟你的界面了:

[TestMethod]
public void Constructor_ExpectInstantiation()
{
    Mock<OrderController> mockOrderController = new Mock<OrderControler>();
    var checkoutManager = new CheckoutManager(mockOrderController.Object);

    Assert.IsNotNull( checkoutManager );
}

这样,OrderController 的构造函数将永远不会被调用(它是一个模拟)并且它不会干扰您对CheckoutManager 的测试。如果需要测试一些与它的交互,可以SetupVerify具体方法使用Moq。

【讨论】:

    【解决方案2】:

    您将无法对此代码使用 Moq 测试。你可以

    • 通过添加接受 OrderController 的构造函数来修改代码以使其更易于测试
    • 使用更“高级”的测试技术,例如shims.

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多