如何对 ASP.NET Core 控制器或模型对象进行单元测试?

Posted

技术标签:

【中文标题】如何对 ASP.NET Core 控制器或模型对象进行单元测试?【英文标题】:How do you unit test an ASP.NET Core controller or model object? 【发布时间】:2015-07-30 17:40:39 【问题描述】:

我正在尝试在 Visual Studio 2015 中使用 ASP.NET Core MVC(预览期间的 ASP.NET 5,现在称为 ASP.NET)在单元测试中获取一些控制器、模型和存储库(数据访问)C# 类核心)应用程序。

我有以下结构:

   Solution
       |
      src
       |
       |-- ITConsole       <- main app (ASP.NET MVC, DNX 4.5.1)
       |
       `-- ITConsoleTests  <- What kind of project should this be?

MainApp 使用的是DNX 4.5.1,但似乎如果我创建一个标准的 NUnit 单元测试应用程序,它只能作为经典的 .NET Framework 类库使用,针对 .NET Framework 4.5.2,而不是作为一个可以与我的主应用程序一起使用的 Web 类库。

所以,以防万一它可以作为经典的 .NET 框架 Microsoft 单元测试框架项目(.NET 程序集),我尝试手动查找和添加引用(通过添加引用和浏览)以获取 .NET 依赖项解决。我知道 .NET 程序集引用很遗憾是不可传递的。因此,如果 UnitTest.dll 有对 MainApp.dll 的引用,而 MainApp.dll 依赖于 ASP.NET MVC,以及它所依赖的所有其他内容,我必须自己做。这就是我想要做的。

我在我的单元测试项目中添加了对C:\dev\Demo\ITConsole\artifacts\bin\ITConsole\Debug\dnx451\ITConsole.dll 的引用,这样我就可以开始编译代码了。单元测试类可以编译,但它们不运行,可能是因为尝试添加对 ASP.NET 的引用的混乱。

现在,即使我添加了对 Common.Logging.Core 和 Common.Logging 的引用,当我在测试资源管理器上单击“全部运行”时,我仍然收到此错误:

Test Name:    TestStudyLogReadDocument
Test FullName:    ITConsoleTests.ITConsoleTestStudyLog.TestStudyLogReadDocument
Test Source:    C:\dev\Demo\ITConsole\ITConsoleTests\ITConsoleTestStudyLog.cs : line 52
Test Outcome:    Failed
Test Duration:    0:00:00.0712058

Result StackTrace:
at Couchbase.Configuration.Client.ClientConfiguration..ctor()
   at ITConsole.Repository.StudyLogRepository..ctor() in C:\dev\Demo\ITConsole\src\ITConsole\Repository\StudyLogRepository.cs:line 39
   at ITConsoleTests.ITConsoleTestStudyLog.SetupDb() in C:\dev\Demo\ITConsole\ITConsoleTests\ITConsoleTestStudyLog.cs:line 30
   at ITConsoleTests.ITConsoleTestStudyLog.TestStudyLogReadDocument() in C:\dev\Demo\ITConsole\ITConsoleTests\ITConsoleTestStudyLog.cs:line 53
Result Message:
Test method ITConsoleTests.ITConsoleTestStudyLog.TestStudyLogReadDocument threw exception:
System.IO.FileLoadException: Could not load file or assembly 'Common.Logging.Core, Version=3.1.0.0, Culture=neutral, PublicKeyToken=af08829b84f0328e' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)

(在问这个问题的时候......)没有一个 ASP.NET 5 MVC 预览模板可以为您生成单元测试。你甚至可以对一个闪亮的新 ASP.NET Core 应用程序进行单元测试吗?请参阅下面的屏幕截图,例如,在 Visual Studio 2015 中使用 MSTEST 无法使用正常的单元测试开始方式。

【问题讨论】:

在这里询问“你什么时候修复你的产品”问题:social.msdn.microsoft.com/Forums/vstudio/en-US/… 我相信这将在 9 月中旬推出 Beta8 时发挥作用。 同时可以试试这个:xunit.github.io/docs/getting-started-dnx.html 相关但关于 xunit 而不是 nunit:***.com/questions/31121523/… 【参考方案1】:

更新:xUnit 仍然是一个好主意,但这个答案现在已经过时了,因为你可以also use the "standard" MSTEST if you want with ASP.NET core。 (2016 年 6 月 1 日)我发现我仍然更喜欢 xUnit,但这是你的决定。

最新的 xUnit 说明链接:Excellent instructions that may be updated more often than this answer are found at the xUnit wiki.

IDE 解决方法:当 Visual Studio 变得愚蠢并且不会“检测”并显示您的测试时,手动查找并删除 %TEMP%\VisualStudioTestExplorerExtensions

截至 2016 年 5 月,随着 ASP.NET Core 1.0 RC1 最近被 RC2 取代,似乎仍然无法将标准 Microsoft 单元测试框架与 ASP.NET Core(以前称为 ASP.NET 5)一起使用,并且出现了 xUnit是RC1和RC2的不错选择。

您可以使用 xUnit GitHub 项目中的官方说明]2 获取 XUnit.net 单元测试以使用 ASP.NET Core 1.0.0-RC1,该项目具有特定的“.NET Core 入门”案例。

您还可以安装 xUnit 新项目模板,该模板为常规的完整 .NET 和 .NET Core 提供模板化单元测试项目。点击菜单Tools然后Extensions and Updates输入xUnit,找到xUnit Test Projecttemplate并安装template不要安装任何 xUnit 测试运行器;你不需要它。

我创建了一个工作示例并将其上传到Bitbucket:

https://bitbucket.org/wpostma/aspnet5mvc6xunitdemo

如果没有Mercurial,可以从Bitbucket 下载ZIP 文件。

演示包括一项通过的测试和一项失败的测试。

快速总结:

    您拥有 Visual Studio 2015,包括更新 2 和“1.0.0 预览”工具(最新于 2016 年 5 月)。

    创建一个Web 类库不是一个单元测试项目

    向它添加 xUnit 引用,并修复您的 project.json(下面是一个示例)。

    编写你的类(下面的示例)。

    在 IDE 内部或外部使用测试资源管理器运行测试,输入 dnx . tests,然后检查输出(示例如下)。

文件 project.json 用于 1.0.0-rc2 参考演示程序集和 xUnit:

 
  "version": "1.0.0-*",

  "testRunner": "xunit",

  "dependencies": 
    "Microsoft.NETCore.App": 
      "version": "1.0.0-rc2-3002702",
      "type": "platform"
    ,

    "dotnet-test-xunit": "1.0.0-rc2-*",

    "xunit": "2.1.0",


    "YetAnotherWebbyDemo": "1.0.0-*"
  ,

  "frameworks": 
    "netcoreapp1.0": 
      "imports": [
        "dotnet5.6",
        "dnxcore50",
        "portable-net45+win8"
      ]
    
  

单元测试类(whatever.cs):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

using Xunit;

using YetAnotherWebbyDemo.Models;

namespace YetAnotherWebbyDemoTests

    // This project can output the Class library as a NuGet Package.
    // To enable this option, right-click on the project and select the Properties menu item. In the Build tab select "Produce outputs on build".
    public class TestBasics
    
        [Fact]
        public void TestAdd()
        

            TestableModelClass TestMe = new TestableModelClass();


            Assert.True(TestMe.Add(3, 2) == 5, "Basic Math Failure");

            Assert.True(TestMe.Add(-3, -2) == -5, "Basic Math Failure");
        

    

当我们使用 dnx 时,RC1 中的命令行输出示例:

C:\dev\Demo\YetAnotherWebbyDemo\src\YetAnotherWebbyDemoTests>dnx . test

xUnit.net DNX Runner (32-bit DNX 4.5.1)
  Discovering: YetAnotherWebbyDemoTests
  Discovered:  YetAnotherWebbyDemoTests
  Starting:    YetAnotherWebbyDemoTests
    YetAnotherWebbyDemoTests.TestBasics.TestAdd [FAIL]
      Basic Math Failure
      Expected: True
      Actual:   False
      Stack Trace:
        YetAnotherWebbyDemoTestBasics.cs(25,0): at YetAnotherWebbyDemoTests.Test
Basics.TestAdd()
  Finished:    YetAnotherWebbyDemoTests
=== TEST EXECUTION SUMMARY ===
   YetAnotherWebbyDemoTests  Total: 1, Errors: 0, Failed: 1, Skipped: 0, Time: 0.263s

我们使用 dotnet 的 RC2 中的示例输出:

D:\dev\aspnet5mvc6xunitdemo\src\YetAnotherWebbyDemoTests>dotnet test
Project YetAnotherWebbyDemo (.NETCoreApp,Version=v1.0) was previously compiled. Skipping compilation.
Project YetAnotherWebbyDemoTests (.NETCoreApp,Version=v1.0) was previously compiled. Skipping compilation.
xUnit.net .NET CLI test runner (64-bit win10-x64)
  Discovering: YetAnotherWebbyDemoTests
  Discovered:  YetAnotherWebbyDemoTests
  Starting:    YetAnotherWebbyDemoTests
    YetAnotherWebbyDemoTests.TestBasics.TestAdd [FAIL]
      Basic Math Failure
      Expected: True
      Actual:   False
      Stack Trace:
        D:\dev\aspnet5mvc6xunitdemo\src\YetAnotherWebbyDemoTests\YetAnotherWebbyDemoTestBasics.cs(26,0): at YetAnotherWebbyDemoTests.TestBasics.TestAdd()
  Finished:    YetAnotherWebbyDemoTests
=== TEST EXECUTION SUMMARY ===
   YetAnotherWebbyDemoTests  Total: 1, Errors: 0, Failed: 1, Skipped: 0, Time: 0.205s
SUMMARY: Total: 1 targets, Passed: 0, Failed: 1.

【讨论】:

我按照您的步骤操作,效果很好!需要注意的一些事项:为了更新我的 project.json,我从原始项目中复制了“框架”,并从您的示例中复制了“命令”。保存和恢复包后,我可以添加对被测项目的引用。然后我通过 nuget 添加了 xunit 和 xunit.runner.dnx(必须包含预览版本)。 是的,好点。我的示例仅适用于使用我正在使用的框架的人。我在这里只列出了 dnx451,因为在我的情况下,我有一些依赖项不适用于 coreclr。 您的TestableModelClass 是否包含控制器类? 对于 XUnit 测试运行器依赖项,您应该使用:“dotnet-test-xunit”:“1.0.0-rc2-*”。此示例中使用的那个 (1.0.0-rc2-build10015) 在针对 net461 时有一个重大错误。 这里有一篇关于 .NET Core 1.0 RTM 中 MSTest 的更新文章:blogs.msdn.microsoft.com/visualstudioalm/2016/09/01/…【参考方案2】:

xUnit 团队在更新他们的文档方面做得很好。

为了始终更新信息,请参阅 xUnit 文档:

Getting Started with xUnit.net

【讨论】:

【参考方案3】:

随着 RC2 的发布,xUnit 集成不再适用于我的项目(现在已修复此问题,请参阅 cmets)。为了能够测试我的项目,我切换到 NUnit。它似乎支持 RC2,并且有一个轻量级的测试运行程序 NUnitLite。

基本上,您需要将 NUnitLite 托管到控制台应用程序中并使用“dotnet run”启动它。

添加以下依赖项:

"dependencies": 
    "NUnit": "3.2.1",
    "NUnitLite": "3.2.1",

要启动测试运行器,您需要将此代码添加到 program.cs 文件中:

public class Program

    public static void Main(string[] args)
    
        new AutoRun().Execute(args);
    

【讨论】:

它确实适用于 RC2。请参阅我的更新答案。无需切换到 NUNIT。 Warren,我的项目使用 net 4.6.1 和 xunit 测试运行器的版本 "dotnet-test-xunit": "1.0.0-rc2-build10015" 使用 net461 使测试运行器崩溃。我指的是这个错误:github.com/dotnet/cli/issues/3103 不过,构建 10025 解决了这个特定的错误,并且在控制台和 VS2015 上运行良好。所以现在我回到了 XUnit。 显然 NUNIT 目前对于 ASP.NET 内核来说是一个糟糕的选择。但希望到 3.4+ 时会更好。 github.com/nunit/nunit/issues/1555

以上是关于如何对 ASP.NET Core 控制器或模型对象进行单元测试?的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET Core 模型未通过 AJAX 绑定到控制器

如何将我自己的类注入到 ASP.NET MVC Core 的控制器中?

ASP.Net Core MVC 如何针对强类型模型发布未知数量的字段

请问使用vscode搭建asp.net core mvc,如何根据模型类新建包含增删改查的控制器呢?

ASP.NET Core 中的模型绑定

如何将 ASP.NET Core 5 Web API 控制器操作的失败模型验证结果包装到另一个类中并将响应返回为 OK