NSubstitute ReturnsForAnyArgs 返回 null 但不应该返回
NSubstitute ReturnsForAnyArgs is returning null but shouldn't
我的测试用例有问题,我正在尝试模拟 ICacheProvider
的 return 但它总是 returnsnull
.
[Fact]
public void Raise_ShoultReturnTrue_IfItsInCache()
{
var cacheProvider = Substitute.For<ICacheProvider>();
cacheProvider.Fetch(Arg.Any<string>(), default(Func<IEnumerable<int>>)).ReturnsForAnyArgs(GetFakeCacheDB());
//I was expecting the var below to contain the data from GetFakeCacheDB method
var cacheProviderReturn = cacheProvider.Fetch("anything", returnEmpty);
//there is more stuff here but doesnt matter for the question
}
private HashSet<int> returnEmpty()
{
return new HashSet<int>();
}
private IEnumerable<int> GetFakeCacheDB()
{
var cacheData = new List<int>()
{
57352,
38752
};
return cacheData;
}
public interface ICacheProvider
{
void Add<T>(string key, T item);
void Add<T>(string key, T item, DateTime? absoluteExpiry, TimeSpan? relativeExpiry);
T Fetch<T>(string key, Func<T> dataLookup);
T Fetch<T>(string key, Func<T> dataLookup, DateTime? absoluteExpiry, TimeSpan? relativeExpiry);
void Remove<T>(string key);
}
我的测试用例有什么问题?
模拟方法参数的配置预期与传递给它的不匹配,因此它将 return 为空。
您当前的期望值是 default(Func<IEnumerable<int>>)
,默认值是 null
,但在执行模拟时,您传递了一个与配置期望值不匹配的实际函数。
对第二个参数也使用Arg.Any
,使模拟期望在执行时更加灵活。
cacheProvider
.Fetch(Arg.Any<string>(), Arg.Any<Func<IEnumerable<int>>>())
.ReturnsForAnyArgs(GetFakeCacheDB());
测试失败的原因是存根调用与实际调用不同运行。由于通用参数,这很难看到,但如果您明确指定它们,您将得到如下内容:
// Arrange
cacheProvider.Fetch<IEnumerable<int>>(/* ... */).ReturnsForAnyArgs(GetFakeCacheDB());
// Act
var cacheProviderReturn = cacheProvider.Fetch<HashSet<int>>("anything", returnEmpty);
.NET 将 Fetch<IEnumerable<int>>()
和 Fetch<HashSet<int>>
视为两种不同的方法,因此虽然第一行已针对任何参数存根为 return GetFakeCacheDB()
,但第二个方法尚未配置,将 return null
。有关更多说明,请参阅 this post。
要使测试按预期进行,请确保通用调用签名匹配,方法是显式指定通用,或确保传递的参数产生正确的通用。
// Option 1: explicit generic
var cacheProviderReturn = cacheProvider.Fetch<IEnumerable<int>>("anything", returnEmpty);
// where `returnEmpty` is `Func<HashSet<int>>`
// Option 2: keep stubbed call the same, and change `returnEmpty` return type
// from `HashSet<int>` to `IEnumerable<int>` to make sure it results
// in correct generic being called.
private IEnumerable<int> returnEmpty() {
return new HashSet<int>();
}
我的测试用例有问题,我正在尝试模拟 ICacheProvider
的 return 但它总是 returnsnull
.
[Fact]
public void Raise_ShoultReturnTrue_IfItsInCache()
{
var cacheProvider = Substitute.For<ICacheProvider>();
cacheProvider.Fetch(Arg.Any<string>(), default(Func<IEnumerable<int>>)).ReturnsForAnyArgs(GetFakeCacheDB());
//I was expecting the var below to contain the data from GetFakeCacheDB method
var cacheProviderReturn = cacheProvider.Fetch("anything", returnEmpty);
//there is more stuff here but doesnt matter for the question
}
private HashSet<int> returnEmpty()
{
return new HashSet<int>();
}
private IEnumerable<int> GetFakeCacheDB()
{
var cacheData = new List<int>()
{
57352,
38752
};
return cacheData;
}
public interface ICacheProvider
{
void Add<T>(string key, T item);
void Add<T>(string key, T item, DateTime? absoluteExpiry, TimeSpan? relativeExpiry);
T Fetch<T>(string key, Func<T> dataLookup);
T Fetch<T>(string key, Func<T> dataLookup, DateTime? absoluteExpiry, TimeSpan? relativeExpiry);
void Remove<T>(string key);
}
我的测试用例有什么问题?
模拟方法参数的配置预期与传递给它的不匹配,因此它将 return 为空。
您当前的期望值是 default(Func<IEnumerable<int>>)
,默认值是 null
,但在执行模拟时,您传递了一个与配置期望值不匹配的实际函数。
对第二个参数也使用Arg.Any
,使模拟期望在执行时更加灵活。
cacheProvider
.Fetch(Arg.Any<string>(), Arg.Any<Func<IEnumerable<int>>>())
.ReturnsForAnyArgs(GetFakeCacheDB());
测试失败的原因是存根调用与实际调用不同运行。由于通用参数,这很难看到,但如果您明确指定它们,您将得到如下内容:
// Arrange
cacheProvider.Fetch<IEnumerable<int>>(/* ... */).ReturnsForAnyArgs(GetFakeCacheDB());
// Act
var cacheProviderReturn = cacheProvider.Fetch<HashSet<int>>("anything", returnEmpty);
.NET 将 Fetch<IEnumerable<int>>()
和 Fetch<HashSet<int>>
视为两种不同的方法,因此虽然第一行已针对任何参数存根为 return GetFakeCacheDB()
,但第二个方法尚未配置,将 return null
。有关更多说明,请参阅 this post。
要使测试按预期进行,请确保通用调用签名匹配,方法是显式指定通用,或确保传递的参数产生正确的通用。
// Option 1: explicit generic
var cacheProviderReturn = cacheProvider.Fetch<IEnumerable<int>>("anything", returnEmpty);
// where `returnEmpty` is `Func<HashSet<int>>`
// Option 2: keep stubbed call the same, and change `returnEmpty` return type
// from `HashSet<int>` to `IEnumerable<int>` to make sure it results
// in correct generic being called.
private IEnumerable<int> returnEmpty() {
return new HashSet<int>();
}