重构类使其可注入/可模拟

时间:2018-11-27 19:27:14

标签: c# .net .net-core

我真的很努力地适当地重构我的课程,以便进行注入。 这是我正在谈论的课程:

internal class OCRService : IDisposable, IOCRService
{
    private const TextRecognitionMode RecognitionMode = TextRecognitionMode.Handwritten;
    private readonly ComputerVisionClient _client;

    public OCRService(string apiKey)
    {
        _client = new ComputerVisionClient(new ApiKeyServiceClientCredentials(apiKey))
        {
            Endpoint = "https://westeurope.api.cognitive.microsoft.com"
        };
    }

    public async Task<List<Line>> ExtractTextAsync(byte[] image)
    {
        //Logic with _client here
    }
}

我真的不知道在哪里初始化ComputerVisionClient。我正在考虑以下选项:

  • ComputerVisionClient设为可在注入后设置的公共属性。
  • 将apikey放入配置文件中,然后在构造函数中读取它。

问题是我想模拟该服务,但是当我模拟它时,它仍然调用连接到ComputerVisionClient的构造函数。

1 个答案:

答案 0 :(得分:1)

根据体系结构的其余部分,您有几种选择。最简单的方法是将ComputerVisionClient(如果可以创建,则将IComputerVisionClient注入到构造函数中,并在测试中对其进行模拟。

public class OCRService : IOCRService, IDisposable
{
    public OCRService(IComputerVisionClient client)
    {
        _client = client;
    }
}

如果由于某种原因必须在构造函数中创建客户端,则可以创建工厂并将其注入:

internal class ComputerVisionClientFactory : IComputerVisionClientFactory
{
    public GetClient(string apiKey)
    {
        return new ComputerVisionClient(new ApiKeyServiceClientCredentials(apiKey))
        {
            Endpoint = "https://westeurope.api.cognitive.microsoft.com"
        };
    }
}

// ...
internal class OCRService : IOCRService, IDisposable
{
    public OCRService(string apiKey, IComputerVisionClientFactory clientFactory)
    {
        _client = clientFactory.GetClient(apiKey);
    }
}

如@maccettura所建议的,您还可以通过创建包含获取密钥逻辑的apiKey并将IOCRServiceConfiguration传递给OCRService的构造函数来进一步抽象ComputerVisionFactoryinternal class OCRServiceConfiguration : IOCRServiceConfiguration { public OCRServiceConfiguration(string apiKey) { ApiKey = apiKey; } public string ApiKey { get; } } ,具体取决于您的体系结构。天真:

GmailApp.getMessageById(messageId).forward(recipients)