我正在编写一个依赖于扩展方法结果的测试,但我不希望该扩展方法的未来失败会破坏此测试.模拟这个结果似乎是显而易见的选择,但是Moq似乎没有提供一种覆盖静态方法的方法(扩展方法的要求).与Moq.Protected和Moq.Stub有类似的想法,但它们似乎没有为这种情况提供任何东西.我错过了什么或者我应该以不同的方式去做这件事吗?
这是一个简单的例子,通常会对"不可覆盖的成员的无效期望"失败.这是需要模拟扩展方法的一个不好的例子,但它应该这样做.
public class SomeType {
int Id { get; set; }
}
var ListMock = new Mock<List<SomeType>>();
ListMock.Expect(l => l.FirstOrDefault(st => st.Id == 5))
.Returns(new SomeType { Id = 5 });
Run Code Online (Sandbox Code Playgroud)
至于任何可能建议我使用Isolator的TypeMock迷们:我很欣赏这项努力,因为看起来TypeMock可能会被蒙住眼睛和醉酒,但我们的预算不会很快增加.
我想要做的是为I1构建一个moq - 这很好......但是在我测试的方法过程中使用这个模拟我需要将它转换为I2才能访问一些不在的属性I1
Interface I1
{ int AProperty{get;set;}}
Interface I2
{int AnotherProperty{get;set;}}
Run Code Online (Sandbox Code Playgroud)
然后我有一些对象
Class O1 : I1 {}
Run Code Online (Sandbox Code Playgroud)
和
Class O2 : O1 , I2 {}
Run Code Online (Sandbox Code Playgroud)
问题是,当我有一个I2实现对象的实例时,我可以将它转换为I1,以便访问通过该接口实现的方法.在代码中,这不是问题,并且每个标志都按预期工作.
在该类上编写单元测试时,唯一的问题就出现了.
接口还公开了一个名为GetNewInstance的方法,该方法返回一个初始化的实现对象实例,该实例对象被转换为IGetNewInstance接口...我通常可以模拟这个并使其自行返回(因此我继续使用模拟对象).
但是,当您尝试将此类型I2的返回对象转换为I1时,将引用空引用 - 这是有意义的,因为实现I2的模拟对象不会从继承I1的任何内容继承.
问题是我如何强制模拟对象同时从I1和I2继承?
我有一个api服务,调用另一个API服务.当我设置Mock对象时,它失败并出现错误:
NotSupportedException:expression引用不属于模拟对象的方法.
这是代码:
private Mock<IEnumerable<ICarrierApiService<AccountSearchModel>>> _mockCarrierService;
private Mock<IApiService<AccountSearchModel>> _mockApiService;
[SetUp]
public void SetUp()
{
_mockApiService = new Mock<IApiService<AccountSearchModel>>();
_mockCarrierService = new Mock<IEnumerable<ICarrierApiService<AccountSearchModel>>>();
_mockApiService.Setup(x => x.GetFromApiWithQuery(It.IsAny<string>())).Returns(ApiValue());
// Error occurred when call _mockApiService.GetFromApiWithQuery() in .Select()
_mockCarrierService.Setup(x => x
.Select(s => s
.GetFromApiWithQuery(It.IsAny<string>())).ToList())
.Returns(new List<IQueryable<AccountSearchModel>> { ApiValue() });
}
Run Code Online (Sandbox Code Playgroud)
我用Moq阅读表达式测试,但它对我的情况不起作用.如果我删除它_mockCarrierService.Setup(),测试用例可以运行但是失败,NullReferenceException因为它没有有效的List<IQueryable<AccountSearchModel>>设置.
知道我怎么能做到这一点?
脚注:当前的解决方案
FWIW,这是我目前使用的解决方案.我很乐意更好地解决这个问题(直到Moq开始支持模拟扩展方法).
private List<ICarrierApiService<AccountSearchModel>> _mockCarrierService;
private AccountSearchController _mockController;
private Mock<ICarrierApiService<AccountSearchModel>> _mockApiService;
[SetUp]
public void SetUp()
{
_mockApiService = …Run Code Online (Sandbox Code Playgroud) 我有一个接收 ILogger 的类,我想模拟 LogInformation 调用,但这是一个扩展方法。我如何为此进行适当的设置调用?
我正在尝试创建一个模拟(使用Moq),IServiceProvider以便我可以测试我的存储库类:
public class ApiResourceRepository : IApiResourceRepository
{
private readonly IServiceProvider _serviceProvider;
public ApiResourceRepository(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
_dbSettings = dbSettings;
}
public async Task<ApiResource> Get(int id)
{
ApiResource result;
using (var serviceScope = _serviceProvider.
GetRequiredService<IServiceScopeFactory>().CreateScope())
{
var context = serviceScope.ServiceProvider.GetRequiredService<ConfigurationDbContext>();
result = await
context.ApiResources
.Include(x => x.Scopes)
.Include(x => x.UserClaims)
.FirstOrDefaultAsync(x => x.Id == id);
}
return result;
}
}
Run Code Online (Sandbox Code Playgroud)
我创建Mock对象的尝试如下:
Mock<IServiceProvider> serviceProvider = new Mock<IServiceProvider>();
serviceProvider.Setup(x => x.GetRequiredService<ConfigurationDbContext>())
.Returns(new ConfigurationDbContext(Options, StoreOptions));
Mock<IServiceScope> serviceScope = new Mock<IServiceScope>(); …Run Code Online (Sandbox Code Playgroud) 我正试图IMemoryCache用Moq 嘲笑.我收到这个错误:
Moq.dll中出现"System.NotSupportedException"类型的异常,但未在用户代码中处理
附加信息:表达式引用不属于模拟对象的方法:x => x.Get <String>(It.IsAny <String>())
我的嘲弄代码:
namespace Iag.Services.SupplierApiTests.Mocks
{
public static class MockMemoryCacheService
{
public static IMemoryCache GetMemoryCache()
{
Mock<IMemoryCache> mockMemoryCache = new Mock<IMemoryCache>();
mockMemoryCache.Setup(x => x.Get<string>(It.IsAny<string>())).Returns("");<---------- **ERROR**
return mockMemoryCache.Object;
}
}
}
Run Code Online (Sandbox Code Playgroud)
为什么我会收到这个错误?
这是测试中的代码:
var cachedResponse = _memoryCache.Get<String>(url);
Run Code Online (Sandbox Code Playgroud)
哪种_memoryCache类型IMemoryCache
我如何模拟_memoryCache.Get<String>(url)上面的内容并让它返回null?
编辑:我怎么做同样的事情,但为 _memoryCache.Set<String>(url, response);?我不介意它返回什么,我只需要将方法添加到mock中,这样它就不会在调用时抛出.
我试着回答这个问题的答案:
mockMemoryCache
.Setup(m => m.CreateEntry(It.IsAny<object>())).Returns(null as ICacheEntry);
Run Code Online (Sandbox Code Playgroud)
因为在memoryCache扩展中它显示它CreateEntry在内部使用Set.但是"对象引用没有设置为对象的实例"是错误的.
扩展方法不适合测试(这里描述:使用Moq模拟扩展方法,http://www.clariusconsulting.net/blogs/kzu/archive/2009/12/22/Howtomockextensionmethods.aspx).
但是可能有一些模拟Unity方法的解决方案?在我的情况下,我有以下功能:
public class MyManager
{
public MyManager(IUnityContainer container) : base(container) { }
public IResult DoJob(IData data)
{
IMyLog log = MyContainer.Resolve<IMyLog>();
... use log.Id ...
MyContainer.Resolve<...>();//usage for other purposes...
}
Run Code Online (Sandbox Code Playgroud)
我想确定'DoJob'方法总是从容器中获取'IMyLog'对象,但不是来自其他来源......我怎么能测试它?
我最初的想法是改变'DoJob'方法的实现和使用:
IMyLog log = UnityContainer.Resolve(typeof(IMyLog)) as IMyLog;
Run Code Online (Sandbox Code Playgroud)
但'Resolve(Type t,...)'也是一种扩展方法......
欢迎任何想法.
PS请注意,"我的日志"对象是远离MyManager.DoJob创建的...
GetString(IStringLocalizer, String, Object[])我有一个测试类,它在某个时候使用扩展方法本地化字符串
除了测试之外,以下内容将有效
public class ClassToTest
{
private readonly IStringLocalizer<SharedResource> _localizer;
public AnalyticsLogic(IStringLocalizer<SharedResource> localizer)
{
_localizer = localizer;
}
public async Task<string> SomeMethod()
{
return _localizer.GetString("key", DateTime.Today)); // "My Date: 31.10.2018" - will return null when testing
}
public async Task<string> SomeMethod2()
{
return _localizer.GetString("key"); // "My Date: {0:d}"
}
}
Run Code Online (Sandbox Code Playgroud)
这就是我建立测试的方式:
public class ClassToTestTest
{
private readonly ClassToTest _testee;
private readonly Mock<IStringLocalizer<SharedResource>> _localizerMock = new Mock<IStringLocalizer<SharedResource>>();
public ClassToTestTest()
{
_testee = new ClassToTest(_localizerMock.Object);
_localizerMock.Setup(lm => lm["key"]).Returns(new LocalizedString("key", …Run Code Online (Sandbox Code Playgroud) moq ×7
c# ×6
unit-testing ×6
mocking ×3
.net-core ×2
asp.net-core ×2
.net ×1
expression ×1
inheritance ×1
interface ×1
linq ×1
localization ×1
logging ×1