第一件事的第一......你需要模拟_bookManager
作为此方法的依赖。
_bookManager
从哪里来?据推测这是一个班级财产。所以它应该提供一些方法来使用模拟。你应该可能使用构造函数注入,但如果你不熟悉ASP.NET MVC中的依赖关系,那么它现在可能会过于复杂。注射财产也应该如此。事情是这样的:
public class MyController
{
private SomeType _bookManager;
public SomeType BookManager
{
get { return _bookManager; }
set { _bookManager = value; }
}
public async Task<ActionResult> Archive()
{
// your method
}
}
想必也是有代码在类在使用它之前,否则初始化_bookManager
别处。你将要修改该逻辑,以便它不覆盖任何提供的模拟。一种对我来说经常效果好的模式是使用属性本身,即使是内部的属性,也可以在属性中进行惰性初始化。事情是这样的:
public class MyController
{
private SomeType _bookManager;
public SomeType BookManager
{
get
{
if (_bookManager == null)
_bookManager = new SomeType();
return _bookManager;
}
set { _bookManager = value; }
}
public async Task<ActionResult> Archive()
{
// IMPORTANT: Use "BookManager" instead of "_bookManager"
}
}
这里的想法是,如果您为BookManager
提供一个模拟(或任何依赖实现),那么代码将使用它。否则,它会使用你正在使用的任何东西。
既然您的课程设置为允许使用模拟,您需要创建一个模拟。有许多嘲笑图书馆可用。我个人使用RhinoMocks。
模拟的目的是提供预期的,定义的行为。这是因为...
您正在测试Archive()
。您是不测试BookManager.GetArchiveBooks()
使用您选择的嘲弄库,在您的测试,你将设立的SomeType
实例(或任何你喜欢的类型叫,很明显)返回从定义和预期的结果GetArchiveBooks()
。根据这个结果,你可以预测你正在测试的方法的结果并验证它产生的结果。
从广义上说,你的测试将是这个样子:
// arrange
var bookManager = MockRepository.GenerateMock<SomeType>();
// TODO: configure the object to return a known result from GetArchiveBooks()
var controller = new MyController();
controller.BookManager = bookManager;
// act
var result = await controller.Archive();
// assert
// TODO: inspect the result to ensure it contains what you expect
对于您所选择的嘲弄库,看看设立了方法的“存根”一些例子被称为(在这种情况下为GetArchiveBooks()
)。
为了检查结果,首先你要在调试器中逐步完成这个测试,看看result
实际上有什么。一个视图结果有很多属性,我不知道它们在我头顶。但是如果你在调试器中检查它,你应该能够在其中一个属性中找到你的模型,以及如果你愿意的话你可能会验证的潜在的其他事情。 (取决于你想在这个测试中声明多少事情。)
此处的目标是确保返回的模型是,正好是您期望它基于模拟依赖关系的已知行为。如果是,则该方法通过测试。
编辑:我只注意到在方法的第二依赖性:
HttpContext.User.Identity.GetUserId()
现代ASP.NET MVC的实现可以提供一些有益的方式来嘲笑HttpContext
为好,虽然我不熟悉我的头顶。最糟糕的情况是,你只是暴露另一个注射属性来嘲笑它。事情是这样的:
private string _userID;
public string UserID
{
get
{
if (string.IsNullOrWhiteSpace(_userID))
_userID = HttpContext.User.Identity.GetUserId();
return _userID;
}
set { _userID = value; }
}
然后在动作方法,你能使用该财产而不是直接调用HttpContext
。在你的测试中,作为“安排”步骤的一部分,你会提供一个模拟字符串。这是很简单的:
controller.UserID = "testUser";
正如你可以在这一点看,可测试性所有关于依赖管理。每个单独的可测试代码应该与任何和所有的依赖关系隔离,无论它们有多小。 (如从HttpContext
获取用户标识。)"Invert" those dependencies允许代码提供信息,而不是让您的可测试代码负责获取信息。
From [Help](http://stackoverflow.com/help/on-topic):提问作业帮助的问题必须包括您迄今为止解决问题所做的工作摘要,以及你正在解决它的困难。 –
你当然可以看看像Autofac这样的IoC,并使用Moq框架来模拟_bookManager类。 –