gpt4 book ai didi

c# - 从部分模拟对象返回模拟对象不起作用

转载 作者:太空宇宙 更新时间:2023-11-03 20:59:59 25 4
gpt4 key购买 nike

我正在编写一个单元测试,我试图在其中尝试部分模拟服务。我的意思是我希望服务的一种方法返回一个不同的模拟对象,而另一种方法表现正常。这是我正在测试的方法:

public async Task<List<string>> GetDeletedRecordIds<T>(DateTime startDate)
where T : ISalesForceObject
{
List<string> result;
try
{
var client = await this.GetForceClient();
var init = await client.GetDeleted<DeletedRecordRootObject>(typeof(T).Name, startDate, DateTime.Now);
result = init?.DeletedRecords.Select(d => d.Id).ToList();
}
catch (Exception e)
{
this._logger.LogError(LoggingEvents.GENERAL_ERROR, e, "GetDeletedRecordIds");
throw;
}

return result;
}

这是我需要返回模拟对象的方法:

public async Task<IForceClient> GetForceClient()
{
ForceClient forceClient = null;
try
{
var auth = new AuthenticationClient();

var consumerKey = this._settingService.GetSetting("SalesForceConsumerKey");
var consumerSecret = this._settingService.GetSetting("SalesForceConsumerSecret");
var password = this._settingService.GetSetting("SalesForcePassword");
var securityToken = this._settingService.GetSetting("SalesForceSecurityToken");
var username = this._settingService.GetSetting("SalesForceUsername");
var tokenUrl = $"{this._settingService.GetSetting("SalesForceUrl")}/services/oauth2/token";

await auth.UsernamePasswordAsync(
consumerKey,
consumerSecret,
username,
password + securityToken,
tokenUrl);

forceClient = new ForceClient(auth.InstanceUrl, auth.AccessToken, auth.ApiVersion);
}
catch (Exception e)
{
this._logger.LogError(LoggingEvents.GENERAL_ERROR, e, $"GetForceClient");
throw;
}

return forceClient;
}

这是我目前在单元测试中的内容:

        var mockForceClient = new Mock<IForceClient>();
mockForceClient
.Setup(
i => i.GetDeleted<DeletedRecordRootObject>(
It.IsAny<string>(),
It.IsAny<DateTime>(),
It.IsAny<DateTime>())).ReturnsAsync(deletedRecordRootObject);

var mockService = new Mock<IForceDotComService>();
mockService.Setup(m => m.GetDeletedRecordIds<sf.Account>(It.IsAny<DateTime>()))
.Returns(async (DateTime d) => await this._service.GetDeletedRecordIds<sf.Account>(d));
mockService.Setup(m => m.GetForceClient())
.ReturnsAsync(mockForceClient.Object);

目前,测试在 GetDeletedRecordIds 中运行,直到它调用 GetForceClient 方法。然后它没有返回模拟的 ForceClient 对象,而是实际尝试运行当然会失败的方法。

在此先感谢您的帮助。

解决方案:这是我解决问题的方法。

首先,我创建了一个返回 ForceClient 的服务,如下所示:

public class ForceClientService : IForceClientService
{
private readonly ILogger _logger;

private readonly ISettingService _settingService;

public ForceClientService(
ILogger<ForceClientService> logger,
ISettingService settingService)
{
this._logger = logger;
this._settingService = settingService;
}

public async Task<IForceClient> GetForceClient()
{
ForceClient forceClient = null;
try
{
var auth = new AuthenticationClient();

var consumerKey = this._settingService.GetSetting("SalesForceConsumerKey");
var consumerSecret = this._settingService.GetSetting("SalesForceConsumerSecret");
var password = this._settingService.GetSetting("SalesForcePassword");
var securityToken = this._settingService.GetSetting("SalesForceSecurityToken");
var username = this._settingService.GetSetting("SalesForceUsername");
var tokenUrl = $"{this._settingService.GetSetting("SalesForceUrl")}/services/oauth2/token";

await auth.UsernamePasswordAsync(
consumerKey,
consumerSecret,
username,
password + securityToken,
tokenUrl);

forceClient = new ForceClient(auth.InstanceUrl, auth.AccessToken, auth.ApiVersion);
}
catch (Exception e)
{
this._logger.LogError(LoggingEvents.GENERAL_ERROR, e, $"GetForceClient");
throw;
}

return forceClient;
}
}

然后我改变了我正在测试的方法:

public async Task DeleteRecord<TSf>(TSf record)
where TSf : ISalesForceObject
{
try
{
var client = await this._forceClientService.GetForceClient();
var response = await client.DeleteAsync(typeof(TSf).Name, record.Id);
if (!response)
{
throw new Exception($"Error deleting record with ID {record.Id}");
}
}
catch (Exception e)
{
this._logger.LogError(LoggingEvents.GENERAL_ERROR, e, $"ForceDotComService.DeleteRecord");
throw;
}
}

然后我重建了我的模拟来模拟依赖项与方法:

var mockForceClient = new Mock<IForceClient>();
mockForceClient
.Setup(
i => i.GetDeleted<DeletedRecordRootObject>(
It.IsAny<string>(),
It.IsAny<DateTime>(),
It.IsAny<DateTime>())).ReturnsAsync(deletedRecordRootObject);

var mockLogger = new Mock<ILogger<ForceDotComService>>();
var mockForceClientService = new Mock<IForceClientService>();
mockForceClientService.Setup(m => m.GetForceClient()).ReturnsAsync(mockForceClient.Object);

this._service = new ForceDotComService(mockLogger.Object, mockForceClientService.Object);

它现在按预期工作。非常感谢您的帮助!

最佳答案

this.GetForceClient() 提取到它自己的由抽象支持的服务中

public IForceClientProvider {
Task<IForceClient> GetForceClient();
}

然后,您将重构当前被测类,以通过构造函数注入(inject)显式依赖于该接口(interface)。

public class ForceDotComService : IForceDotComService {
private readonly IForceClientProvider provider;

public ForceDotComService(IForceClientProvider provider) {
this.provider = provider;
}

public async Task<List<string>> GetDeletedRecordIds<T>(DateTime startDate)
where T : ISalesForceObject {
List<string> result;
try {
var client = await provider.GetForceClient();
var init = await client.GetDeleted<DeletedRecordRootObject>(typeof(T).Name, startDate, DateTime.Now);
result = init?.DeletedRecords.Select(d => d.Id).ToList();
} catch (Exception e) {
this._logger.LogError(LoggingEvents.GENERAL_ERROR, e, "GetDeletedRecordIds");
throw;
}

return result;
}
}

这将允许您在测试时模拟所需的行为。在实现代码中,您将在 GetForceClient() 方法中拥有与上面相同的代码。

关于c# - 从部分模拟对象返回模拟对象不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46448405/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com