问题描述
private readonly ITenantProvdier _tenantProvider;
//ctor ...
public void ConfigureNewTenants( MultitenantContainer multiTenantContainer )
{
var tenants = _tenantProvider.GetNewTenantsToAdd(); //gets tenants that are just added during the runtime.
foreach( var tenant in tenants )
{
try
{
multiTenantContainer.ConfigureTenant( tenant.Id,someCustomAction);
}
catch( ArgumentNullException exception )
{
// log error and do smth
}
catch( InvalidOperationException exception )
{
// log error and do smth
}
}
}
我的目标是测试 multiTenantContainer
抛出 ArgumentNullException
或 InvalidOperationException
时的代码行为。
我正在使用 NUnit 和 Moq。 并尝试做下一个:
var containerMock = new Mock<MultitenantContainer>();
containerMock
.Setup(c => c.ConfigureTenant(It.IsAny<object>,It.IsAny<Action<ContainerBuilder>>)
.Thows(someException);
但它不起作用,因为方法 ConfigureTenant
有下一个签名:public void ConfigureTenant(object tenantId,Action<ContainerBuilder> configuration)
。并且不能模拟非虚拟类方法。
我尝试使用 virtual new
方法创建派生类。它没有帮助。
解决方法
伙计。在您的示例中,您将收到这样的错误:
Unsupported expression: c => c.ConfigureTenant(It.IsAny<object>(),It.IsAny<Action<ContainerBuilder>>())
Non-overridable members (here: MultitenantContainer.ConfigureTenant) may not be used in setup / verification expressions.
Moq
说他不能模拟非虚方法。
我们有解决方案吗? - 是的!
您需要从方法中提取 interface
并模拟它或将方法标记为 virtual
。在您的情况下,最好选择 interface
选项。
让我们试试吧!
我尝试创建类似于您的示例:
- 在接口中包装方法
public interface IConfigureNewTenants
{
void ConfigureNewTenants(MultitenantContainer multiTenantContainer,int id,Action<ContainerBuilder> action);
}
- 为其创建实现
public class NewTenats : IConfigureNewTenants
{
public void ConfigureNewTenants(MultitenantContainer multiTenantContainer,Action<ContainerBuilder> action)
{
multiTenantContainer.ConfigureTenant(id,action);
}
}
- 模拟方法
// Arrnage
configureNewTenantsMock
.Setup(x => x.ConfigureNewTenants(multitenantContainer.Object,It.IsAny<int>(),It.IsAny<Action<ContainerBuilder>>()))
.Throws<InvalidOperationException>();
- 并进行测试!
// Act
Action act = () => manager.ConfigureNewTenants(multitenantContainer.Object);
// Assert
act.Should().Throw<InvalidOperationException>()
.And.Message
.Should().Be("InvalidOperationExceptionMessage");
这是解决问题的主要思路。 完整的解决方案有更多的代码行,这是我为它创建的方式 gist。