C# - 使用 Guid 参数引发事件的单元测试方法

C# - Unit test method that raises event with Guid argument

我正在尝试弄清楚如何测试这种情况,但一无所获。

我有一个侦听器服务,当在邮槽中检测到文件时会触发以下事件:

IEventDispatcher _dispatcher;
IListener _mailslotListener;

public Service (IEventDispatcher dispatcher, IMailslotListener mailslotListener) {
  _dispatcher = dispatcher;
  _mailslotListener = mailslotListener;
}

public async void _Listener_OnFileDetected(object sender, MailslotArgs) {
  string filePath = args.Message;

  Directory.CreateDirectory(TempLocation);

  FileId = Guid.NewGuid();
  string tempPath = Path.Combine(TempLocation, FileId.ToString());
    
  File.Move(filePath, tempPath);

  await _dispatcher.DispatchEvent("documentPrinted", FileId);
}

这会将传入的文件移动到一个临时位置并使用 Guid 重命名它。在我的测试中,我试图验证文件是否已成功移动,但我不确定如何访问使用并传递给 _dispatcher.DispatchEvent 调用的 Guid。

我能够验证事件是否已引发,但这是我所了解的,因为在测试中声明相等性时,随机 Guid 的值似乎是一个问题。

[Test]
public void OnFileDetected_CallsDispatchEvent()
{
  Directory.CreateDirectory(tempPath);
  listenerService._Listener_OnFileDetected(null, new MailslotArgs(testFilePath));

  mockEventDispatcher.Verify(m => m.DispatchEvent("fileDetected", 
                                  It.IsAny<Guid>()), 
                                  Times.Once);
}

这是 static 初始值设定项的典型问题。它被称为 DateTime.Now 变体,但结果是相同的。

问题是,由于它是静态的,因此很难模拟该方法的输出。

由于它是在实现中使用的,因此 GUID 的结果保存在其中,并且没有简单的方法来访问它。

一种常见的方法是创建一个包装器 class + 接口,以公开 Guid.NewGuid() 方法。

使用这种方法,您可以完全控制 Guid 生成 - 您只需要使用适当的 class.

//The interface
public interface IGuidGenerator
{
     Guid NewGuid();
}

//Use in the application
public class GuidGenerator: IGuidGenerator
{
    public Guid NewGuid()
    {
        return Guid.NewGuid();
    }
}

//Use in the test scenario
public class TestGuidGenerator: IGuidGenerator
{
    public Guid NewGuid()
    {
        return new Guid("dddddddd-dddd-dddd-dddd-dddddddddddd");
    }
}

如果您使用的是 IoC 框架,只需注册接口和 class,然后将生成器传递给服务即可:

public Service (IEventDispatcher dispatcher, 
                IMailslotListener mailslotListener, 
                IGuidGenerator guidGenerator) 
{
   _dispatcher = dispatcher;
   _mailslotListener = mailslotListener;
   _guidGenerator = guidGenerator;
}

DateTime.Now变体,其实是常用作面试题。 这里有更多关于这个主题的内容:https://dvoituron.com/2020/01/22/UnitTest-DateTime/