【问题标题】:How to mock constructor in c# xUnit test case?如何在 c# xUnit 测试用例中模拟构造函数?
【发布时间】:2019-07-29 19:40:25
【问题描述】:

您好,我正在开发 C# 应用程序。我正在为控制器级别编写单元测试用例。下面是我的控制器代码。

 public IActionResult TriggerProductEventCheck([FromQuery(Name = "timeout-secs")] int timeoutS = 120)
    {
      int productEventsCount = 0;
      if (productService.ProcessingEnabled)
      {
        var cts = new CancellationTokenSource();
        cts.CancelAfter(timeoutS * 1000);
        lock (SyncObject)
        {
          this.consumerClient.Subscribe(this.productEventTopicName);
          while (!cts.IsCancellationRequested)
          {
            var productEvent = this.eventDispatcher.Consume();
            long kafkaOffSet = productEvent.Offset.Value;
            Product product = new Product(productEvent, log);
            if (product.Options == null)
            {
              break;
            }

            if (product != null)
            {
              productService.ProcessProductEvents(product, kafkaOffSet);
            }

            productEventsCount++;
          }
        }
      }

下面是我的单元测试用例。

 public void ShouldReturnIfNoSQSEvents()
      {
        var productEventController = MockProvider.Target<ProductEventController>();
        productEventController.GetDependency<IProductEventService>().ProcessingEnabled.Returns(true);

        productEventController.GetDependency<IEventDispatcher>().Consume().Returns(new Confluent.Kafka.ConsumeResult<string, Avro.Generic.GenericRecord>());

        productEventController.GetDependency<IConsumerClient>().Subscribe("test");
        var productclass = Substitute.For<Product>();
        var response = productEventController.Target.TriggerProductEventCheck() as JsonResult;
        ((int)response.StatusCode).ShouldBe(200);
      }

每当我在单元测试用例之上运行时,控制进入 Product product = new Product(productEvent, log);我想模拟这条特定的线。我可以知道如何处理这种情况吗?任何帮助,将不胜感激。谢谢

【问题讨论】:

  • 嗨,我正在使用 Substitute。
  • 你在哪里设置this.eventDispatcher。也许在控制器构造函数中?
  • 是的,首先我添加了私有只读 IEventDispatcher eventDispatcher;然后在构造函数中我添加了参数 IEventDispatcher eventDispatcher。然后在构造函数中我添加了 this.eventDispatcher = eventDispatcher;
  • 我在启动时在 ConfigureServices 方法中注册我的所有服务。这是 .Net 核心提供的默认 IOC 容器,如果我没记错的话。比如services.AddSingleton()里面的startup;
  • 嗨..如果您需要更多详细信息,请告诉我。

标签: c# xunit


【解决方案1】:

至少有两种方式。

最可取的做法是:添加第二种方法,让您可以注入所需的元素。您可以调用另一种方法来重用代码。第二种方法将用于测试。另一个应该保持原样。

另一种选择是使用允许实现 shim 进行测试的框架。例如: - Moles,“允许用委托替换任何 .NET 方法”。在这里您可以看到一个允许模拟 DateTime 构造函数的示例:Nikolai Tillmann: Moles - Replace any .NET method with a delegate。 - “微软假货”:Isolating Code Under Test with Microsoft Fakes。 - 有一些商业测试框架也支持 shim。

但是,您应该使用第一个建议的解决方案,或者更改软件的设计,例如使用依赖注入,以便您可以轻松控制单元测试中的依赖关系。在您没有任何其他选择的情况下,您应该保留使用 shim,例如在您无法修改其代码的第三方库中注入更改。

您可以在 Google 上搜索“.NET shims testing”以了解有关此技术的更多信息。

【讨论】:

  • 感谢您的回答。因此添加接口并将所有产品构造函数逻辑移动到接口方法中。这是建议的方式对吗?
  • 这将是理想的解决方案。但是,您还没有显示所有代码。也许,在这种特殊情况下,使用“产品工厂方法”注入一个类会更容易。即具有允许您创建Product 的新实例的方法的类。你必须小心同步,使这个方法线程安全。
  • 好的。我可以知道我应该显示哪个代码吗?产品构造函数中的代码?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-24
  • 1970-01-01
  • 2021-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多