简体   繁体   English

如何注入不提供接口和虚拟方法的 class 的假实现?

[英]How to inject a fake implementation of a class providing no interface and no virtual methods?

I'm using the Discord.Net package offering me the DiscordSocketClient class, which currently is a Singleton in my DI container. I'm using the Discord.Net package offering me the DiscordSocketClient class, which currently is a Singleton in my DI container. I need several methods from the instance我需要实例中的几种方法

  • Task LoginAsync(TokenType tokenType, string token, bool validateToken = true)
  • Task StartAsync()
  • Task LogoutAsync()
  • Task StopAsync()

Given this example class consuming the methods鉴于此示例 class 使用方法

public sealed class ConsumingClass
{
    private readonly DiscordSocketClient _discordSocketClient;
    
    public ConsumingClass(DiscordSocketClient discordSocketClient)
    {
        _discordSocketClient = discordSocketClient;
    }
    
    public override async Task Initialize(CancellationToken cancellationToken)
    {
        await _discordSocketClient.LoginAsync(TokenType.Bot, "my-token");
        await _discordSocketClient.StartAsync();
    }
    
    public override async Task TearDown(CancellationToken cancellationToken)
    {
        await _discordSocketClient.LogoutAsync();
        await _discordSocketClient.StopAsync();
    }
}

I want to create tests using XUnit and Moq to ensure the instance of ConsumingClass works as expected.我想使用 XUnit 和 Moq 创建测试,以确保ConsumingClass的实例按预期工作。

Unfortunately DiscordSocketClient does not offer an interface so I can't inject a mock implementation to my tests.不幸的是, DiscordSocketClient不提供接口,因此我无法为我的测试注入模拟实现。

Also the methods are not virtual, so it is not possible to create an instance of Mock<DiscordSocketClient> and use .Setup() to setup mock implementations.此外,这些方法不是虚拟的,因此无法创建Mock<DiscordSocketClient>的实例并使用.Setup()来设置模拟实现。

So how can I verify in my testcase, that the client methods have been called once?那么如何在我的测试用例中验证客户端方法已被调用一次呢? Eg _discordSocketClientMock.Verify(discordSocketClient => discordSocketClient.LoginAsync(), Times.Once());例如_discordSocketClientMock.Verify(discordSocketClient => discordSocketClient.LoginAsync(), Times.Once());

Do I have to create an interface IMyDiscordSocketClient providing those methods and a class another class MyDiscordSocketClient inheriting from DiscordSocketClient and implementing the interface and use that?我是否必须创建一个接口IMyDiscordSocketClient提供这些方法和一个 class 另一个 class MyDiscordSocketClient继承自DiscordSocketClient并实现接口并使用它? Or are there any better ways?或者有没有更好的方法?

If DiscordSocketClient does not have (public) virtual members, you cannot really derive from it either.如果DiscordSocketClient没有(公共)虚拟成员,您也不能真正从中派生。 Your last suggestion is however probably still the best possibility you have, except that MyDiscordSocketClient should not derive from DiscordSocketClient , but aggregate one.但是,您的最后一个建议可能仍然是您拥有的最好的可能性,除了MyDiscordSocketClient不应该从DiscordSocketClient派生,而是聚合一个。


public class MyDiscordSocketClient: IMyDiscordSocketClient
{
    private DiscordSocketClient _client;
    public MyDiscordSocketClient(DiscordSocketClient client)
    {
        _client = _client;
    }
    
    public async Task Initialize(CancellationToken cancellationToken)
    {
         _client.Initialize(cancellationToken);
    }

    // etc...
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM