请查看此代码:
public UserRepository GetUserRepositoryMock()
{
// mock all UserRepository instances.
var userRepositoryMock = Isolate.Fake.Instance<UserRepository>();
Isolate.Swap.AllInstances<UserRepository>().With(userRepositoryMock);
// make all public UserRepository members throw a NotSupportedException.
Isolate.WhenCalled(() => userRepositoryMock.Select(null)).WillThrow(new NotSupportedException());
Isolate.WhenCalled(() => userRepositoryMock.SelectOne(null)).WillThrow(new NotSupportedException());
Isolate.WhenCalled(() => userRepositoryMock.Save(null)).WillThrow(new NotSupportedException());
Isolate.WhenCalled(() => userRepositoryMock.Remove(null)).WillThrow(new NotSupportedException());
// ... et cetera until all public members of UserRepository will throw NotSupportedException.
}
[TestMethod]
public void ActivateUser_UserNotFound_ThrowsException()
{
var userRepositoryMock = GetUserRepositoryMock();
// override one of the public UserRepository members to return a specific value.
Isolate.WhenCalled(() => userRepositoryMock.SelectOne(null)).DoInstead(context =>
{
return null;
});
// call ActivateUser implementation.
RegistrationServices.ActivateUser("foo@bar.com", "password", "activation-code");
}
这段代码实际 为 UserRepository 的所有公共成员抛出NotSupportedException。
我想要这段代码让 UserRepository 的所有公共成员抛出 NotSupportedException 除了 SelectOne()函数,它返回 null 。
我想确保 RegistrationServices 的 ActivateUser()功能不会调用除之外的 UserRepository 的任何功能我明确指定的SelectOne()函数。
如果是这样,例如通过更改 ActivateUser()的实现来调用 UserRepository 的 Save(),不改变相应的* ActivateUser_UserNotFound_ThrowsException *测试,我希望测试失败,因为更改可能会引入意外行为。通过这种方式,我可以将我的应用程序与第三方完全隔离,并将编码错误降至最低。
我对此代码及其背后原理的疑问是:
答案 0 :(得分:2)
注意:我在Typemock工作
您可以通过以下几种方法来测试您想要的内容。
例如,您可以使用Isolate.Verify
API确保没有对您的虚假对象进行特定调用。
这将允许您不明确指定其他方法的返回,因为您可以确保它们不会发生:
[Test, Isolated]
public void ActivateUser_UserNotFound_ThrowsException()
{
var userRepositoryMock = Isolate.Fake.Instance<UserRepository>();
Isolate.Swap.AllInstances<UserRepository>().With(userRepositoryMock);
Isolate.WhenCalled(() => userRepositoryMock.SelectOne(null)).WillReturn(null);
// call ActivateUser implementation.
RegistrationServices.ActivateUser("foo@bar.com", "password", "activation-code");
Isolate.Verify.WasNotCalled(() => userRepositoryMock.Save(null));
Isolate.Verify.WasNotCalled(() => userRepositoryMock.Remove(null));
}
Isolator的WhenCalled()
方法行为按照定义的顺序排列,这意味着在原始测试中,第一次SelectOne
将抛出异常,第二次及其上将返回null
希望有所帮助,如果您有其他问题,请随时通过支持与我们联系,或者在这里!
答案 1 :(得分:1)
我不确定你为什么要这样做。您最好在测试中设置模拟对象,并为每个测试创建一个新的模拟对象。
这看起来似乎更多的工作,但使用上面的方法将使您的测试难以遵循,GetUserRepositoryMock
方法越来越有用,因为您添加了更多需要稍微不同的行为的测试。< / p>
如果您想要做的只是验证那些方法没有被调用,那么您可以使用Isolate.Verify.WasNotCalled(x=>x.Select(null));
为每个方法执行此操作。我认为这是一种更好的方法,可以设置所有方法来抛出异常。
您可以通过GetUserRepositoryMock
方法获取大量布尔值来指定哪些方法可以使用throw NotImplementedException
进行模拟,所有默认值均为true,从而获得您想要的内容。然后,您可以使用命名参数来指定您不想设置的参数。这些方面的东西:
public UserRepository GetUserRepositoryMock(bool mockSelect=true, bool mockSelectOne=true, bool mockSave=true ... etc etc)
{
// mock all UserRepository instances.
var userRepositoryMock = Isolate.Fake.Instance<UserRepository>();
Isolate.Swap.AllInstances<UserRepository>().With(userRepositoryMock);
// make all public UserRepository members throw a NotSupportedException.
if(mockSelect)
Isolate.WhenCalled(() => userRepositoryMock.Select(null)).WillThrow(new NotSupportedException());
if (mockSelectOne)
Isolate.WhenCalled(() => userRepositoryMock.SelectOne(null)).WillThrow(new NotSupportedException());
if(mockSave)
Isolate.WhenCalled(() => userRepositoryMock.Save(null)).WillThrow(new NotSupportedException());
// ... et cetera until all public members of UserRepository will throw NotSupportedException where the corresponding flag is true.
}
然后你可以在测试中调用它,你不希望模拟SelectOne:
[TestMethod]
public void ActivateUser_UserNotFound_ThrowsException()
{
var userRepositoryMock = GetUserRepositoryMock(mockSelectOne:false);
// override one of the public UserRepository members to return a specific value.
Isolate.WhenCalled(() => userRepositoryMock.SelectOne(null)).DoInstead(context =>
{
return null;
});
// call ActivateUser implementation.
RegistrationServices.ActivateUser("foo@bar.com", "password", "activation-code");
}
所以你只需要使用命名参数指定你想要与默认值不同的东西。
我并不是说我特别喜欢这个解决方案,并且使用一些TypeMocks自己的方法可能会有更好的解决方案,但这应该可以满足您的需求。您可以根据标志定制此方法以实际对每个事物进行Isolate.Verify.WasNotCalled()
检查。