我开始使用Moq框架并且非常喜欢它。我正在编写一些控制器测试,它们有几个服务和接口来安排我的控制器进行测试。我想更多地模块化它,并认为这将是一项微不足道的任务,但事实证明它比我想象的要复杂一些。
这是一个简单的单元测试,我必须展示一个例子:
[Test]
public void Get_SignIn_Should_Return_View()
{
#region //TODO: figure out how to extract this out to avoid duplicate code
// Arrange
var membershipService = new Mock<IMembershipService>();
var formsService = new Mock<IFormsAuthenticationService>();
var userService = new Mock<IUserService>();
var dictService = new Mock<IDictionaryService>();
var shoppingBasketService = new Mock<IShoppingBasketService>();
//Create the service provider mock and pass in the IRepositoryFactory so that it isn't instantiating real repositories
var repoFactory = new Mock<IRepositoryFactory>();
var serviceProvider = new Mock<ServiceProvider>( (IRepositoryFactory)repoFactory.Object );
var context = new Mock<HttpContextBase> { DefaultValue = DefaultValue.Mock };
var sessionVars = new Mock<SessionVars>();
AccountController controller = new AccountController( serviceProvider.Object, sessionVars.Object )
{
FormsService = formsService.Object,
MembershipService = membershipService.Object,
UserService = userService.Object,
DictionaryService = dictService.Object,
ShoppingService = shoppingBasketService.Object
};
controller.ControllerContext = new ControllerContext()
{
Controller = controller,
RequestContext = new RequestContext( context.Object, new RouteData() )
};
#endregion
// Act
ActionResult result = controller.SignIn();
// Assert
Assert.IsInstanceOf<ViewResult>( result );
}
我希望能够做的是将#region
中的所有内容都解压缩到辅助方法或[Setup]方法中,但如果我这样做,那么我就无法访问为每个模拟服务设置期望。
这里是否有我遗漏的东西,或者我是否真的必须在每个单元测试中复制并粘贴这一段编码?
答案 0 :(得分:3)
尝试使用上下文设置所有模拟,然后使用继承上下文的test fixtures。将测试放在这些灯具和violà中!此代码可能不适合您正在使用的框架。如果它是NUnit那么它将是。但理论就在那里。
public abstract class MembershipTestContext
{
var membershipService = new Mock<IMembershipService>();
var formsService = new Mock<IFormsAuthenticationService>();
var userService = new Mock<IUserService>();
var dictService = new Mock<IDictionaryService>();
var shoppingBasketService = new Mock<IShoppingBasketService>();
//Create the service provider mock and pass in the IRepositoryFactory so that it isn't instantiating real repositories
var repoFactory = new Mock<IRepositoryFactory>();
var serviceProvider = new Mock<ServiceProvider>( (IRepositoryFactory)repoFactory.Object );
var context = new Mock<HttpContextBase> { DefaultValue = DefaultValue.Mock };
var sessionVars = new Mock<SessionVars>();
[SetUp]
AccountController controller = new AccountController( serviceProvider.Object, sessionVars.Object )
{
FormsService = formsService.Object,
MembershipService = membershipService.Object,
UserService = userService.Object,
DictionaryService = dictService.Object,
ShoppingService = shoppingBasketService.Object
};
controller.ControllerContext = new ControllerContext()
{
Controller = controller,
RequestContext = new RequestContext( context.Object, new RouteData() )
};
}
[TestFixture]
public class when_getting_sign_in : MembershipContext
{
[Test]
public void Should_return_view()
{
// Act
ActionResult result = controller.SignIn();
// Assert
Assert.IsInstanceOf<ViewResult>(result);
}
[Test]
public void Should_do_another_test()
{
... another test etc
}
}
答案 1 :(得分:1)
您可以做的一件事是使用Mock.Get
方法(http://api.moq.me/html/C6B12927.htm)来检索给定对象实例的模拟。
另一种选择是重构代码并在测试类的实例变量中存储对模拟对象的引用(如果测试类中的所有测试都需要它们)或者可能是简单的数据结构(如果只需要一些测试)它们)。