我是测试和.net的绝对初学者,我需要尽快为学校项目测试这种方法。
这是代码:
// GET: Books/Archive
public async Task<ActionResult> Archive()
{
var usersBooks = await _bookManager.GetArchiveBooks(Guid.Parse(HttpContext.User.Identity.GetUserId()));
var result = usersBooks.Select(ConvertArchiveBookToViewModel).ToList();
return View(new ArchiveViewModel
{
Books = result
});
}
任何答案都非常有用,谢谢你们:)
答案 0 :(得分:3)
首先要做的事情......你需要模仿_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
对于您选择的模拟库,请查看一些示例来设置&#34; stub&#34;对于被调用的方法(在本例中为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
。在你的测试中,作为&#34;安排&#34;的一部分。一步,你会提供一个模拟字符串。这很简单:
controller.UserID = "testUser";
正如您在此处所看到的,可测试性是所有关于依赖关系管理。每个可测试的代码片段都应该与任何依赖关系隔离,无论它们有多小。 (例如从HttpContext
获取用户ID。)"Invert" those dependencies以允许代码提供信息,而不是让可测试代码负责获取信息。