简体   繁体   English

有人可以告诉我如何测试此方法

[英]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 testing BookManager.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.

相关问题 谁能告诉我如何从ActionFilterAttribute方法访问DbContext - Can someone tell me how to access the DbContext from an ActionFilterAttribute method 有人能告诉我如何为子弹做冷却吗? - Can someone tell me how to make a cooldown for the bullet? 有人可以告诉我如何在C#上修复此错误 - Can someone tell me how to fix this error on C# 有人可以告诉我如何将文件包含在点网核心的多项目模板中吗? - Can someone tell me how to include files with multi-project templates for dot net core? 有人能告诉我这意味着WriteLine(“{0,-12}”) - Can someone tell me what this means WriteLine(“{0,-12}”) 有人可以告诉我为什么它在查询中引发语法错误吗? - Can someone tell me why is it throwing syntax error in the query? 有人可以告诉我AddForce和transform.translate之间的区别吗? - Can someone tell me the difference between AddForce and transform.translate? 有人可以告诉我我的班级标题出了什么问题吗? - Can someone tell me what the problem is with my class header? 有人可以告诉我为什么这个正则表达式不起作用吗? - Can someone tell me why this regular expression isnt working? 有人能告诉我这段代码使用的是哪个版本的 Angular 吗? - Can someone tell me which version of Angular is this code using?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM