2015-11-12 50 views
0

我是一个绝对的初学者,测试和.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 
     }); 
} 

任何答案将是真正的帮助,并感谢您:)

+2

From [Help](http://stackoverflow.com/help/on-topic):提问作业帮助的问题必须包括您迄今为止解决问题所做的工作摘要,以及你正在解决它的困难。 –

+0

你当然可以看看像Autofac这样的IoC,并使用Moq框架来模拟_bookManager类。 –

回答

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 

对于您所选择的嘲弄库,看看设立了方法的“存根”一些例子被称为(在这种情况下为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允许代码提供信息,而不是让您的可测试代码负责获取信息。

+0

非常感谢你的回复真的有用:) –

相关问题