gpt4 book ai didi

c# - 使用 Xunit 进行 .Net 核心测试

转载 作者:太空宇宙 更新时间:2023-11-03 12:09:55 24 4
gpt4 key购买 nike

这是我第一次编写测试用例,我并没有被卡住,也不确定如何继续。

我有以下 API。在下面的示例中,我有 2 个要执行测试的端点。

public class ValuesController : Controller
{
//This interface is used to setup dynamo db and connection to aws
private IDynamoDbClientInitialization _clientAccessor;
private static string dynamoDbTable = string.Empty;

public ValuesController(IOptions<Dictionary<string, string>> appSettings, IDynamoDbClientInitialization clientAccessor)
{
var vals = appSettings.Value;
dynamoDbTable = vals["dynamoDbTable"];
_clientAccessor = clientAccessor;
}

[HttpGet("api/data")]
public async Task<List<MyModel>> GetAllData(string type, string status)
{
List<ScanCondition> conditions = new List<ScanCondition>();
conditions.Add(new ScanCondition("Type", ScanOperator.Equal, type));
conditions.Add(new ScanCondition("Status", ScanOperator.Equal, status));
var response = await _clientAccessor.GetContext().ScanAsync<MyModel>(conditions, AWSHelperMethods.GetDynamoDbOperationConfig(dynamoDbTable)).GetRemainingAsync();
return results.Select(x => x.UpdatedBy.ToLower()).ToList();
}

[HttpPost("api/save")]
public async Task<IActionResult> SaveData([FromBody] List<MyModel> listData, string input, string name, string type)
{
List<MyModel> model = null;
foreach (var data in listData)
{
//populating data here
await _clientAccessor.GetContext().SaveAsync(data, AWSHelperMethods.GetDynamoDbOperationConfig(dynamoDbTable));
}

return Ok();
}
}

public class DynamoDbClientInitialization : IDynamoDbClientInitialization
{
private readonly DynamoDbClientSettings settings;
private DynamoDBContext _awsContext;

public DynamoDbClientInitialization(IOptions<DynamoDbClientSettings> options)
{
settings = options?.Value;
}

public DynamoDBContext GetContext()
{
//Check is context already exists. If not create a new one.
if(_awsContext != null)
{
return _awsContext;
}
else
{
var creds = AWSHelperMethods.SetAwsCredentials(settings.Id, settings.Password);
var dynamoClient = AWSHelperMethods.GetDynamoDbClient(creds, settings.Region);
_awsContext = AWSHelperMethods.GetDynamoDbContext(dynamoClient);

return _awsContext;
}
}
}

public static class AWSHelperMethods
{
public static BasicAWSCredentials SetAwsCredentials(string awsId, string awsPassword)
{
var creds = new BasicAWSCredentials(awsId, awsPassword);
return creds;
}

public static AmazonDynamoDBClient GetDynamoDbClient(BasicAWSCredentials creds, RegionEndpoint awsDynamoDbRegion)
{
var client = new AmazonDynamoDBClient(creds, awsDynamoDbRegion);
return client;
}

public static DynamoDBContext GetDynamoDbContext(AmazonDynamoDBClient client)
{
var context = new DynamoDBContext(client);
return context;
}

public static DynamoDBOperationConfig GetDynamoDbOperationConfig(string dynamoDbTable)
{
DynamoDBOperationConfig config = new DynamoDBOperationConfig() { OverrideTableName = dynamoDbTable };
return config;
}
}

下面是我添加的xunit项目。在这里,我使用最小起订量来最小化我的 aws 连接和其他连接。问题在下面针对代码的评论中。

public class DataTest
{

[Fact]
public void PassingTest()
{
//Arrange
var dynamoDbTable = "someValue";

//Trying to moq IOptions
var moqOp = new Mock<IOptions<Dictionary<string, string>>>();

//Create an instance to hold desired values
var vals = new Dictionary<string, string>();

//Set expected value
vals["dynamoDbTable"] = dynamoDbTable;

//Setup dependency behavior
moqOp.Setup(_ => _.Value).Returns(vals);

//Trying to moq my connection
var moqDb = new Mock<IDynamoDbClientInitialization>();

//Fake data
List<MyModel> data = new List<MyModel>()
{
//populate as needed
};

moqDb
.Setup(_ => _.GetContext().ScanAsync<MyModel>
(It.IsAny<List<ScanCondition>>(), AWSHelperMethods.GetDynamoDbOperationConfig(dynamoDbTable)).GetRemainingAsync())
.ReturnsAsync(data);

ValuesController controller = new ValuesController(moqOp.Object,
moqDb.Object);

var actual = controller.GetAllData();
}
}

上面我得到的错误是:表达式树不能包含使用可选参数的调用或调用

这是在线

.Setup(_ => _.GetContext().ScanAsync<MyModel>
(It.IsAny<List<ScanCondition>>(), AWSHelperMethods.GetDynamoDbOperationConfig(dynamoDbTable)).GetRemainingAsync())

谁能帮忙解决一下?

---更新---

    public interface IDynamoDbManager
{
Task<List<T>> GetAsync(IEnumerable<ScanCondition> conditions);

Task SaveAsync(T item);
}

最佳答案

An expression tree may not contain a call or invocation that uses optional arguments

您正在尝试“调用”尚未设置 GetContext() 的 ScanAsync 方法。要解决此问题,您必须在尝试设置 ScanAsync() 之前设置 GetContext() 的返回值


这段代码很难测试,所以让我们重构它。

您必须将 _clientAccessor.GetContext() 的直接调用更改为注入(inject) IDynamoDBContext。DynamoDbClientInitialization 没有意义,因为可以轻松替换为 IAmazonDynamoDb。要摆脱冗长的配置阅读代码行,请使用

services.AddAWSService<IAmazonDynamoDB>();

所有对 DynamoDb 的调用都应封装在一个单独的类中,例如 DynamoDbManager

public class DynamoDbManager<T> : DynamoDBContext, IDynamoDbManager<T> where T : class
{
private DynamoDBOperationConfig _config;

public DynamoDbManager(IAmazonDynamoDB client, string tableName): base(client)
{
_config = new DynamoDBOperationConfig()
{
OverrideTableName = tableName
};
}

public Task<List<T>> GetAsync(IEnumerable<ScanCondition> conditions)
{
return ScanAsync<T>(conditions, _config).GetRemainingAsync();
}

public Task SaveAsync(T item)
{
return base.SaveAsync(item, _config);
}
}

现在您的 Controller 将以这种方式更改ValuesController

public class ValuesController : Controller
{
private readonly IDynamoDbManager<MyModel> _dynamoDbManager;
//This interface is used to setup dynamo db and connection to aws
private static string dynamoDbTable = string.Empty;

public ValuesController(IOptions<Dictionary<string, string>> appSettings, IDynamoDbManager<MyModel> dynamoDbManager)
{
_dynamoDbManager = dynamoDbManager;
var vals = appSettings.Value;
dynamoDbTable = vals["dynamoDbTable"];
}

[HttpGet("api/data")]
public async Task<IActionResult> GetAllData(string type, string status)
{
var conditions = new List<ScanCondition>
{
new ScanCondition("Type", ScanOperator.Equal, type),
new ScanCondition("Status", ScanOperator.Equal, status)
};
var result = await _dynamoDbManager.GetAsync(conditions);
var response = result.Select(_ => _.UpdatedBy.ToLower()).ToList();
return Ok(response);
}

[HttpPost("api/save")]
public async Task<IActionResult> SaveData([FromBody] List<MyModel> listData, string input, string name, string type)
{
foreach (var data in listData)
{
//populating data here
await _dynamoDbManager.SaveAsync(data);
}
return Ok();
}
}

重构完成,开始编写单元测试ValuesControllerTests

public class ValuesControllerTests
{
private Mock<IDynamoDbManager<MyModel>> _dbManager;
private ValuesController _valuesController;

public ValuesControllerTests()
{
var mockRepository = new MockRepository(MockBehavior.Loose);
_dbManager = mockRepository.Create<IDynamoDbManager<MyModel>>();
var options = new OptionsWrapper<Dictionary<string, string>>(new Dictionary<string, string>()
{
{"dynamoDbTable", nameof(MyModel) }
});
_valuesController = new ValuesController(options, _dbManager.Object);

}

[Fact]
public async Task GetAllData_ShouldSelectUpdateByInLowerCase()
{
//
var searchResult = new List<MyModel>()
{
new MyModel() {UpdatedBy = "UpdatedBy1"}
};
_dbManager
.Setup(_ => _.GetAsync(It.Is<List<ScanCondition>>(list => list.Count == 2)))
.ReturnsAsync(searchResult);

//

var result = await _valuesController.GetAllData("typeValue", "statusValue");

//
var okResult = result as OkObjectResult;
Assert.NotNull(okResult);
var values = okResult.Value as List<string>;
Assert.Contains("updatedby1", values);
}

[Fact]
public async Task SaveData_ShouldCallSaveForAllRequestedData()
{
//
var listData = new List<MyModel>()
{
new MyModel(),
new MyModel(),
new MyModel()
};
_dbManager
.Setup(_ => _.SaveAsync(It.IsAny<MyModel>()))
.Returns(Task.CompletedTask);

//

var result = await _valuesController.SaveData(listData, "","", "");

//
_dbManager.Verify(_ => _.SaveAsync(It.IsAny<MyModel>()), Times.Exactly(3));
}
}

就是这样,我为每个 Controller 操作做了两个测试,因为它更容易理解——如果你真的只需要一个测试,你可以很容易地加入它们

关于c# - 使用 Xunit 进行 .Net 核心测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52879141/

24 4 0
文章推荐: python - FormEncode 中的 ForEach 和 NestedVariables 在 Pyramid 中创建表单项数组
文章推荐: c# - PropertyGrid --> 从 List 中选择对象