Moq + xunit + asp.net core: service return 空值
Moq + xunit + asp.net core: service return null value
我在 asp.net 核心应用程序中使用 xUnit 作为测试 运行ner。
这是我的测试理论:
[Theory(DisplayName = "Search advisors by advisorId"),
ClassData(typeof(SearchAdvisorsByIdTestData))]
public async void SearchAdvisors_ByAdvisorId(int brokerDealerId, FilterParams filter)
{
// Arrange
var _repositoryMock = new Mock<IRepository>();
// Do this section means we bypass the repository layer
_repositoryMock
.Setup(x => x.SearchAdvisors(filter.CID.Value, new AdvisorSearchOptions
{
SearchKey = filter.SeachKey,
AdvisorId = filter.AdvisorId,
BranchId = filter.BranchId,
City = filter.City,
Skip = filter.Skip,
Limit = filter.Limit,
RadiusInMiles = filter.Limit,
Longitude = filter.Longitude,
Latitude = filter.Latitude
}))
.Returns(Task.FromResult<SearchResults<Advisor>>(
new SearchResults<Advisor>()
{
Count = 1,
Limit = 0,
Skip = 0,
ResultItems = new List<SearchResultItem<Advisor>>() {
//some initialize here
}
})
);
_advisorService = new AdvisorService(_repositoryMock.Object, _brokerDealerRepositoryMock, _brokerDealerServiceMock);
// Action
var model = await _advisorService.Search(brokerDealerId, filter);
Assert.True(model.AdvisorResults.Count == 1);
Assert.True(model.AdvisorResults[0].LocationResults.Count > 0);
}
这样的服务
public async Task<ViewModelBase> Search(int brokerDealerId, FilterParams filter)
{
var opts = new AdvisorSearchOptions
{
SearchKey = filter.SeachKey,
AdvisorId = filter.AdvisorId,
BranchId = filter.BranchId,
City = filter.City,
Skip = filter.Skip,
Limit = filter.Limit,
RadiusInMiles = filter.Limit,
Longitude = filter.Longitude,
Latitude = filter.Latitude
};
var searchResults = await _repository.SearchAdvisors(filter.CID.Value, opts); // line 64 here
if (searchResults.Count == 0 && Utils.IsZipCode(filter.SeachKey))
{
}
//Some other code here
return model;
}
问题出现在服务中的 运行 行 64 之后。尽管我已经在测试中模拟了 _repository,但我总是得到 searchResults 的空值。
我哪里错了?
提前致谢。
SearchAdvisors()
模拟的参数匹配器不起作用,因为您传递了 AdvisorSearchOptions
的不同实例。第一个实例在 _repositoryMock.Setup()
语句中创建,第二个实例在 Search()
方法本身中创建。
有几种方法可以解决这个问题:
1.If 您不关心验证传递给存储库的实例 of AdvisorSearchOptions
是否正确填充,只需在模拟设置中使用 It.IsAny<AdvisorSearchOptions>()
匹配器:
_repositoryMock.Setup(x => x.SearchAdvisors(filter.CID.Value, It.IsAny<AdvisorSearchOptions>()))
.Returns(/*...*/);
2.In 之前的情况测试不会验证 AdvisorSearchOptions
是否正确填写。为此,您可以覆盖 AdvisorSearchOptions
class 中的 Object.Equals()
方法,以便模拟调用将匹配不同的实例:
public class AdvisorSearchOptions
{
// ...
public override bool Equals(object obj)
{
var cmp = obj as AdvisorSearchOptions;
if (cmp == null)
{
return false;
}
return SearchKey == cmp.SearchKey && AdvisorId == cmp.AdvisorId &&
/* ... compare all other fields here */
}
}
3.Another 验证传递给 mock 的对象的方法是通过 Mock 回调保存实例,然后比较所需字段:
AdvisorSearchOptions passedSearchOptions = null;
_repositoryMock
.Setup(x => x.SearchAdvisors(filter.CID.Value, It.IsAny<AdvisorSearchOptions>()))
.Returns(Task.FromResult<SearchResults<Advisor>>(
new SearchResults<Advisor>()
{
Count = 1,
Limit = 0,
Skip = 0,
ResultItems = new List<SearchResultItem<Advisor>>() {
//some initialize here
}
})
)
.Callback<int, AdvisorSearchOptions>((id, opt) => passedSearchOptions = opt);
// Action
// ...
Assert.IsNotNull(passedSearchOptions);
Assert.AreEqual(filter.SearchKey, passedSearchOptions.SearchKey);
Assert.AreEqual(filter.AdvisorId, passedSearchOptions.AdvisorId);
// Check all other fields here
// ...
我在 asp.net 核心应用程序中使用 xUnit 作为测试 运行ner。 这是我的测试理论:
[Theory(DisplayName = "Search advisors by advisorId"),
ClassData(typeof(SearchAdvisorsByIdTestData))]
public async void SearchAdvisors_ByAdvisorId(int brokerDealerId, FilterParams filter)
{
// Arrange
var _repositoryMock = new Mock<IRepository>();
// Do this section means we bypass the repository layer
_repositoryMock
.Setup(x => x.SearchAdvisors(filter.CID.Value, new AdvisorSearchOptions
{
SearchKey = filter.SeachKey,
AdvisorId = filter.AdvisorId,
BranchId = filter.BranchId,
City = filter.City,
Skip = filter.Skip,
Limit = filter.Limit,
RadiusInMiles = filter.Limit,
Longitude = filter.Longitude,
Latitude = filter.Latitude
}))
.Returns(Task.FromResult<SearchResults<Advisor>>(
new SearchResults<Advisor>()
{
Count = 1,
Limit = 0,
Skip = 0,
ResultItems = new List<SearchResultItem<Advisor>>() {
//some initialize here
}
})
);
_advisorService = new AdvisorService(_repositoryMock.Object, _brokerDealerRepositoryMock, _brokerDealerServiceMock);
// Action
var model = await _advisorService.Search(brokerDealerId, filter);
Assert.True(model.AdvisorResults.Count == 1);
Assert.True(model.AdvisorResults[0].LocationResults.Count > 0);
}
这样的服务
public async Task<ViewModelBase> Search(int brokerDealerId, FilterParams filter)
{
var opts = new AdvisorSearchOptions
{
SearchKey = filter.SeachKey,
AdvisorId = filter.AdvisorId,
BranchId = filter.BranchId,
City = filter.City,
Skip = filter.Skip,
Limit = filter.Limit,
RadiusInMiles = filter.Limit,
Longitude = filter.Longitude,
Latitude = filter.Latitude
};
var searchResults = await _repository.SearchAdvisors(filter.CID.Value, opts); // line 64 here
if (searchResults.Count == 0 && Utils.IsZipCode(filter.SeachKey))
{
}
//Some other code here
return model;
}
问题出现在服务中的 运行 行 64 之后。尽管我已经在测试中模拟了 _repository,但我总是得到 searchResults 的空值。
我哪里错了?
提前致谢。
SearchAdvisors()
模拟的参数匹配器不起作用,因为您传递了 AdvisorSearchOptions
的不同实例。第一个实例在 _repositoryMock.Setup()
语句中创建,第二个实例在 Search()
方法本身中创建。
有几种方法可以解决这个问题:
1.If 您不关心验证传递给存储库的实例 of AdvisorSearchOptions
是否正确填充,只需在模拟设置中使用 It.IsAny<AdvisorSearchOptions>()
匹配器:
_repositoryMock.Setup(x => x.SearchAdvisors(filter.CID.Value, It.IsAny<AdvisorSearchOptions>()))
.Returns(/*...*/);
2.In 之前的情况测试不会验证 AdvisorSearchOptions
是否正确填写。为此,您可以覆盖 AdvisorSearchOptions
class 中的 Object.Equals()
方法,以便模拟调用将匹配不同的实例:
public class AdvisorSearchOptions
{
// ...
public override bool Equals(object obj)
{
var cmp = obj as AdvisorSearchOptions;
if (cmp == null)
{
return false;
}
return SearchKey == cmp.SearchKey && AdvisorId == cmp.AdvisorId &&
/* ... compare all other fields here */
}
}
3.Another 验证传递给 mock 的对象的方法是通过 Mock 回调保存实例,然后比较所需字段:
AdvisorSearchOptions passedSearchOptions = null;
_repositoryMock
.Setup(x => x.SearchAdvisors(filter.CID.Value, It.IsAny<AdvisorSearchOptions>()))
.Returns(Task.FromResult<SearchResults<Advisor>>(
new SearchResults<Advisor>()
{
Count = 1,
Limit = 0,
Skip = 0,
ResultItems = new List<SearchResultItem<Advisor>>() {
//some initialize here
}
})
)
.Callback<int, AdvisorSearchOptions>((id, opt) => passedSearchOptions = opt);
// Action
// ...
Assert.IsNotNull(passedSearchOptions);
Assert.AreEqual(filter.SearchKey, passedSearchOptions.SearchKey);
Assert.AreEqual(filter.AdvisorId, passedSearchOptions.AdvisorId);
// Check all other fields here
// ...