[英]Can someone tell me how to test this method
I am an absolute beginner to testing and .net and I need to test this method as soon as possible for a school project. 我绝对是测试和.net的初学者,我需要针对学校项目尽快测试此方法。
This is the code : 这是代码:
// 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
});
}
Any answer would be really helpful and thank you :) 任何答案都将非常有帮助,谢谢:)
First thing's first... You need to mock _bookManager
as a dependency for this method. 首先,您需要模拟
_bookManager
作为此方法的依赖项。
Where does _bookManager
come from? _bookManager
来自哪里? Presumably it's a class-level property. 大概是一个类级别的属性。 So it should provide some means by which to use a mock.
因此,它应该提供一些使用模拟的方法。 You should likely use constructor injection, but if you're not familiar with wiring up dependencies in ASP.NET MVC then it might get a little too complex for now.
您可能应该使用构造函数注入,但是如果您不熟悉在ASP.NET MVC中连接依赖项,那么现在它可能会变得有点复杂。 An injectable property should work just as well.
可注入属性也应同样起作用。 Something like this:
像这样:
public class MyController
{
private SomeType _bookManager;
public SomeType BookManager
{
get { return _bookManager; }
set { _bookManager = value; }
}
public async Task<ActionResult> Archive()
{
// your method
}
}
Presumably also there is code elsewhere in that class which otherwise initializes _bookManager
before using it. 大概在该类的其他地方也有代码,否则
_bookManager
在使用_bookManager
之前初始化它。 You're going to want to modify that logic a bit so that it doesn't overwrite any supplied mocks. 您将需要稍微修改该逻辑,以免覆盖任何提供的模拟。 One pattern that often works well for me is to use the property itself even internal to the class and to lazy-initialize in the property.
对我而言通常有效的一种模式是使用该属性本身,甚至在类内部使用该属性,并在该属性中进行延迟初始化。 Something like this:
像这样:
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"
}
}
The idea here is that if you supply a mock (or any dependency implementation) for the BookManager
then the code would use that. 这里的想法是,如果为
BookManager
提供模拟(或任何依赖实现),则代码将使用该模拟。 Otherwise it would use whatever you're currently using. 否则,它将使用您当前正在使用的任何东西。
Now that your class is set up for allowing the use of a mock, you need to create a mock. 现在您的类已设置为允许使用模拟,现在您需要创建一个模拟。 There are many mocking libraries available.
有许多可用的模拟库。 Personally I use RhinoMocks.
我个人使用RhinoMocks。
The purpose of a mock is to provide expected, defined behavior. 模拟的目的是提供预期的定义的行为。 This is because...
这是因为...
You are testing
Archive()
.您正在测试
Archive()
。 You are not testingBookManager.GetArchiveBooks()
您没有测试
BookManager.GetArchiveBooks()
Using the mocking library of your choice, in your test you would set up an instance of SomeType
(or whatever your type is called, obviously) to return a defined and expected result from GetArchiveBooks()
. 使用您选择的
SomeType
库,在您的测试中,您将设置SomeType
的实例(或者显然调用了您的类型),以从GetArchiveBooks()
返回定义的预期结果。 Based on that result, you would predict the result of the method you're testing and validate that it produces exactly that result. 根据该结果,您可以预测所测试方法的结果,并验证该方法是否能够准确地产生该结果。
In a broad sense, your test would look something like this: 从广义上讲,您的测试将如下所示:
// 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
For the mocking library of your choice, take a look at some examples for setting up a "stub" for the method being called (in this case GetArchiveBooks()
). 对于您选择的模拟库,请看一些示例,这些示例为正在调用的方法设置“存根”(在本例中为
GetArchiveBooks()
)。
For inspecting the result, first you're going to want to step through this test in a debugger and see what result
actually has. 为了检查结果,首先,您将要在调试器中逐步执行此测试,然后查看实际
result
。 A view result has a lot of properties on it, and I don't know them off the top of my head. 视图结果具有很多特性,但我不知道这些特性如何。 But if you inspect it in a debugger you should be able to find your model in one of those properties, as well as potentially other things you could potentially validate if you want to.
但是,如果您在调试器中对其进行检查,则应该能够在这些属性之一中找到您的模型,并在可能的情况下找到其他可能需要验证的东西。 (Depending on how many things you want to assert in this test.)
(取决于您要在此测试中声明多少内容。)
The goal here is to make sure that the returned model is exactly what you expect it to be based on the known behavior of the mocked dependency. 此处的目标是确保返回的模型与您所期望的模型完全一样 ,该模型基于模拟依赖项的已知行为。 If it is, then the method passes the test.
如果是,则该方法通过测试。
Edit: I just noticed a second dependency in the method: 编辑:我只是注意到该方法中的第二个依赖项:
HttpContext.User.Identity.GetUserId()
Modern ASP.NET MVC implementations may provide some helpful ways to mock HttpContext
as well, though I'm not familiar with that off the top of my head either. 现代的ASP.NET MVC实现也可以提供一些有用的方式来模拟
HttpContext
,尽管我也不是最想知道的方式。 Worst case scenario is that you just expose another injectable property to mock it. 最糟糕的情况是,您只是公开了另一个可注入属性以对其进行模拟。 Something like this:
像这样:
private string _userID;
public string UserID
{
get
{
if (string.IsNullOrWhiteSpace(_userID))
_userID = HttpContext.User.Identity.GetUserId();
return _userID;
}
set { _userID = value; }
}
Then in your action method you would use that property instead of calling the HttpContext
directly. 然后,在您的操作方法中,您将使用该属性, 而不是直接调用
HttpContext
。 And in your test, as part of the "arrange" step, you would supply a mock string. 在测试中,作为“安排”步骤的一部分,您将提供一个模拟字符串。 Which is pretty easy:
这很简单:
controller.UserID = "testUser";
As you can see at this point, testability is all about dependency management. 正如您现在所看到的,可测试性完全取决于依赖性管理。 Each individual testable piece of code should be isolated from any and all dependencies, no matter how small they may be.
每个独立的可测试代码段都应该与所有依赖项隔离开,无论它们有多小。 (Such as getting the user ID from
HttpContext
.) "Invert" those dependencies to allow code to supply the information rather than having your testable code be responsible for getting the information. (例如从
HttpContext
获取用户ID。) “反转”这些依赖关系,以允许代码提供信息,而不是让您的可测试代码负责获取信息。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.