如何使用 MOQ 对象测试 Ninject ConstructorArguments?

2024-03-10

我最近一直在做我的第一个测试驱动开发项目,并一直在学习 Ninject 和 MOQ。这是我第一次尝试这一切。我发现 TDD 方法发人深省,Ninject 和 MOQ 也很棒。我正在从事的项目并不是特别适合 Ninject,因为它是一个高度可配置的 C# 程序,旨在测试 Web 服务接口的使用。

我已将其分解为模块并在整个商店中提供接口,但我仍然发现在从 Ninject 内核获取服务的实现时必须使用大量构造函数参数。例如;

在我的 Ninject 模块中;

Bind<IDirEnum>().To<DirEnum>()

我的 DirEnum 类;

public class DirEnum : IDirEnum
{
    public DirEnum(string filePath, string fileFilter, 
        bool includeSubDirs)
    {
        ....

在我的配置器类(这是主入口点)中,它将所有服务挂钩在一起;

class Configurator
{

    public ConfigureServices(string[] args)
    {
        ArgParser argParser = new ArgParser(args);
        IDirEnum dirEnum = kernel.Get<IDirEnum>(
            new ConstructorArgument("filePath", argParser.filePath),
            new ConstructorArgument("fileFilter", argParser.fileFilter),
            new ConstructorArgument("includeSubDirs", argParser.subDirs)
        );

filePath、fileFilter 和 includeSubDirs 是程序的命令行选项。到目前为止,一切都很好。然而,作为一个认真负责的人,我有一个涵盖这段代码的测试。我想使用最小起订量对象。我为我的测试创建了一个 Ninject 模块;

public class TestNinjectModule : NinjectModule
{
    internal IDirEnum mockDirEnum {set;get};
    Bind<IDirEnum>().ToConstant(mockDirEnum);
}

在我的测试中我这样使用它;

[TestMethod]
public void Test()
{
    // Arrange
    TestNinjectModule testmodule = new TestNinjectModule();
    Mock<IDirEnum> mockDirEnum = new Mock<IDirEnum>();
    testModule.mockDirEnum = mockDirEnum;
    // Act
    Configurator configurator = new Configurator();
    configurator.ConfigureServices();
    // Assert

    here lies my problem! How do I test what values were passed to the
    constructor arguments???

所以上面显示了我的问题。如何测试传递给模拟对象的 ConstructorArguments 的参数是什么?我的猜测是,在这种情况下,Ninject 正在分配 ConstructorArguments,因为 Bind 不需要它们?我可以使用 MOQ 对象对此进行测试,还是需要手动编写一个实现 DirEnum 并接受并“记录”构造函数参数的模拟对象?

注:这段代码是“示例”代码,即我没有逐字复制我的代码,但我认为我已经表达了足够的内容来希望传达问题?如果您需要更多背景信息,请询问!

感谢您的关注。温柔一点,这是我第一次;-)

Jim


您设计应用程序的方式存在一些问题。首先,您直接从代码中调用 Ninject 内核。这被称为服务定位器模式 http://en.wikipedia.org/wiki/Service_locator_pattern and 它被认为是一种反模式 http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx。它使测试您的应用程序变得更加困难,并且您已经经历过这一点。您试图在单元测试中模拟 Ninject 容器,这使事情变得非常复杂。

接下来,您将注入原始类型(string, bool)在你的构造函数中DirEnum类型。我喜欢 MNrydengren 在评论中的表述:

获取“编译时”依赖项 通过构造函数参数和 通过方法的“运行时”依赖关系 参数

我很难猜测该类应该做什么,但是由于您将这些在运行时更改的变量注入到DirEnum构造函数,您最终会得到一个难以测试的应用程序。

有多种方法可以解决这个问题。我想到的两个是方法注入的使用和工厂的使用。哪一种可行取决于您。

使用方法注入,你的Configurator类将如下所示:

class Configurator
{
    private readonly IDirEnum dirEnum;

    // Injecting IDirEnum through the constructor
    public Configurator(IDirEnum dirEnum)
    {
        this.dirEnum = dirEnum;
    }

    public ConfigureServices(string[] args)
    {
        var parser = new ArgParser(args);

        // Inject the arguments into a method
        this.dirEnum.SomeOperation(
            argParser.filePath
            argParser.fileFilter
            argParser.subDirs);
    }
}

使用工厂,您需要定义一个知道如何创建新的工厂IDirEnum types:

interface IDirEnumFactory
{
    IDirEnum CreateDirEnum(string filePath, string fileFilter, 
        bool includeSubDirs);
}

Your Configuration类现在可以依赖于IDirEnumFactory界面:

class Configurator
{
    private readonly IDirEnumFactory dirFactory;

    // Injecting the factory through the constructor
    public Configurator(IDirEnumFactory dirFactory)
    {
        this.dirFactory = dirFactory;
    }

    public ConfigureServices(string[] args)
    {
        var parser = new ArgParser(args);

        // Creating a new IDirEnum using the factory
        var dirEnum = this.dirFactory.CreateDirEnum(
            parser.filePath
            parser.fileFilter
            parser.subDirs);
    }
}

查看这两个示例中如何将依赖项注入到Configurator班级。这被称为依赖注入模式 http://en.wikipedia.org/wiki/Dependency_injection,与服务定位器模式相反,其中Configurator通过调用 Ninject 内核来请求其依赖项。

现在,自从你的Configurator完全不受任何 IoC 容器的影响,您现在可以通过注入所需依赖项的模拟版本来轻松测试此类。

剩下的就是在应用程序顶部配置 Ninject 容器(用 DI 术语来说:成分根 https://stackoverflow.com/questions/6277771/what-is-a-composition-root-in-the-context-of-dependency-injection)。对于方法注入示例,您的容器配置将保持不变,对于工厂示例,您将需要替换Bind<IDirEnum>().To<DirEnum>()符合以下内容:

public static void Bootstrap()
{
    kernel.Bind<IDirEnumFactory>().To<DirEnumFactory>();
}

当然,您需要创建DirEnumFactory:

class DirEnumFactory : IDirEnumFactory
{
    IDirEnum CreateDirEnum(string filePath, string fileFilter, 
        bool includeSubDirs)
    {
        return new DirEnum(filePath, fileFilter, includeSubDirs);
    }        
}

WARNING:请注意,工厂抽象在大多数情况下并不是最好的设计,正如所解释的那样here https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=100.

您需要做的最后一件事是创建一个新的Configurator实例。您可以简单地执行以下操作:

public static Configurator CreateConfigurator()
{
    return kernel.Get<Configurator>();
}

public static void Main(string[] args)
{
    Bootstrap():
    var configurator = CreateConfigurator();

    configurator.ConfigureServices(args);
}

这里我们称之为内核。尽管应该防止直接调用容器,但应用程序中始终至少有一个地方可以调用容器,因为它必须连接所有内容。然而,我们尝试最小化直接调用容器的次数,因为它提高了代码的可测试性。

看看我如何没有真正回答你的问题,但展示了一种非常有效地解决问题的方法。

您可能仍想测试您的 DI 配置。在我看来,这是非常有效的。我在我的应用程序中这样做。但为此,您通常不需要 DI 容器,或者即使您需要,这并不意味着您的所有测试都应该依赖于该容器。这种关系只应存在于测试 DI 配置本身的测试中。这是一个测试:

[TestMethod]
public void DependencyConfiguration_IsConfiguredCorrectly()
{
    // Arrange
    Program.Bootstrap();

    // Act
    var configurator = Program.CreateConfigurator();

    // Assert
    Assert.IsNotNull(configurator);
}

该测试间接依赖于 Ninject,当 Ninject 无法构造新的测试时,该测试将会失败Configurator实例。当您保持构造函数不包含任何逻辑并且仅将其用于将获取的依赖项存储在私有字段中时,您可以运行它,而无需承担调用数据库、Web 服务或其他任何内容的风险。

我希望这有帮助。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 MOQ 对象测试 Ninject ConstructorArguments? 的相关文章

  • 与仅调用依赖函数/类相比,在 FastAPI 中使用 Depends 有哪些优点?

    FastAPI 提供了way https fastapi tiangolo com tutorial dependencies 通过其自己的依赖关系解析机制来管理依赖关系 例如数据库连接 它类似于一个pytest夹具系统 简而言之 您在函数
  • 模拟一个接口 { get;仅(最小起订量)

    我有一个IUnitOfWork包含到我们所有存储库的映射的接口 如下所示 public interface IUnitOfWork IDisposable IRepository
  • 使用机器人框架进行 ATDD

    我想听听其他人使用 Robot Framework 进行自动化验收测试的经验 它的主要优点和缺点是什么以及与其他框架 主要是 Fitnesse 和 Selenium 的比较 将测试的代码是实时的遗留代码 主要是 C 语言 在我撰写本文时 我
  • 如何避免从模拟对象列表返回模拟

    我正在尝试模拟 责任驱动的设计 在对象需要服务来检索其他对象的情况下 我似乎无法避免从模拟返回模拟 一个例子是检查上个月的账单是否已支付的对象 它需要一个检索账单列表的服务 所以我需要在测试中模拟 billRetrievalService
  • 以编程方式注入依赖项asp.net core

    我刚刚开始Asp net core 依赖注入 我的概念可能不准确 这篇 docs asp net 帖子 https docs asp net en latest mvc controllers dependency injection ht
  • DI 容器、工厂还是临时对象的新容器?

    当处理需要仅在运行时知道的数据的对象 例如用户名和密码 时 对象实例化应该在哪里进行 使用 new 在工厂中还是在 DI 容器中 例如 我可以new一旦我有了数据 就得到一个对象 UserCredentials creds new User
  • 使用 Ninject 2 在基本控制器中进行属性注入

    我的 Global aspx 中有以下代码 protected override void OnApplicationStarted AreaRegistration RegisterAllAreas RegisterRoutes Rout
  • 在不使用魔术字符串的情况下将参数传递给 FakeItEasy-mock?

    我一直在使用Moq http code google com p moq 为了满足我过去几年的嘲笑需求 但看了之后假装简单 http code google com p fakeiteasy 我想尝试一下 我经常想测试是否使用正确的参数调用
  • EJB:无接口的依赖注入

    我有这个代码 Local interface IRepo Stateless class Repo implements IRepo class WebS EJB private IRepo repo 并且一切正常 但现在我删除了界面IRe
  • 如何使用 Entity Framework 和 Moq 进行单元测试?

    我是 Moq 新手 希望将其用作数据后备存储 但不接触实时数据库 我的设置如下 UnitOfWork 包含所有存储库 并用于整个应用程序中的数据访问 Repository 代表 DbSet 的直接挂钩 由 DbContext 提供 DbCo
  • Xamarin、Autofac、NavigationService 和 BeginLifetimeScope

    关于带有 autofac 的生命周期范围以及何时在 xamarin 应用程序中使用它们的初学者问题 正如这篇文章中提到的 https nblumhardt com 2011 01 an autofac lifetime primer htt
  • 单元测试 Bash 脚本

    我们的系统除了 Java 代码之外还运行一些 Bash 脚本 既然我们正在努力测试所有可能损坏的东西 并且那些 Bash 脚本可能会损坏 我们想测试它们 问题是很难测试 Bash 脚本 有没有测试 Bash 脚本的方法或最佳实践 或者我们应
  • 使用 asp.net mvc 4 的简单注入器,从另一个程序集加载控制器

    我正在开发一个 asp net mvc 4 站点 使用 Simple Injector 作为 Ioc 工具 这将是一个可插拔的架构 某些控制器和视图位于另一个程序集中 另一个 mvc4 应用程序 Plugin Web dll 从主应用程序中
  • 设置惰性静态变量首先初始化然后分配?

    我意识到static变量是隐式的lazy 这真的很棒 执行以下操作在第一次调用之前不会创建实例 static var test Test 但是 将一个新实例分配给static变量初始化原始实例 然后分配新实例 这对我来说很麻烦 SomeTy
  • PHP 中的依赖注入

    我一直在研究依赖注入 我是在关注某件事还是完全没有关注 代码是好是坏 依赖注入与否 下面的代码是CMS系统的基础 现在有一个名为 page details 的表 其中存储了所有网页 目录 文件结构 htaccess index php cl
  • Mediatr 范围问题

    我正在使用 Mediatr 处理来自队列的消息 我可以得到一个简单的例子来工作 但是 当我尝试将对象注入到我的处理程序中时 我遇到了问题 public class MessageCommandHandler IRequestHandler
  • 使用策略和工厂模式进行依赖注入

    我正在开展一个业余项目 以更好地理解控制反转和依赖注入以及不同的设计模式 我想知道是否有将 DI 与工厂和策略模式结合使用的最佳实践 当策略 从工厂构建 需要每个可能的构造函数和实现不同的参数时 我面临的挑战就出现了 因此 我发现自己在服务
  • 在ConfigureServices中注入依赖

    在我的 ASP Net Core 应用程序中 我需要在以下位置注入一些依赖项 在我的例子中是一个存储库 ConfigureServices method 问题是该方法不允许使用多个参数来注入依赖项 该怎么办呢 这是我的代码 public v
  • ATDD 与 BDD 以及框架的正确使用

    我刚刚开始了解 BDD 的概念 并且已经听了 Scott Bellware 与 Herding Code 人员的演讲 我一直在尝试使用 SpecFlow 并且非常喜欢它 我了解博客文章中描述的 ATDD 和 TDD 之间的区别BDD 工具分
  • UnitTest HttpResponse WriteAsync 和 CopyToAsync

    我想对下一个方法进行单元测试 public static async Task SetResponseBody HttpResponse response string message var originalResponseBody re

随机推荐

  • 为什么 getLocationOnScreen(location) 总是返回 0?

    In my FragmentLayout我有一个LinearLayout具有多个子视图 TextView CardView 我想找到所有的顶部偏移量LinearLayout意见但我总是得到零 这是我的代码 Override public V
  • 部分多键映射的数据结构?

    我的数据由映射到值的键组成 如下所示 Key Value 0 0 0 0 a 0 0 0 1 b 0 1 0 1 c 0 1 1 0 d 我正在寻找一种可以有效地对键执行搜索查询的数据结构 其中查询可以是完整或部分指定键 例如 0 0 0
  • 从 WP7 上的 xna 游戏启动 Internet Explorer

    我想知道是否可以从 Windows Phone 7 上运行的 XNA 游戏启动 Internet Explorer 我想将我的玩家重定向到我的网站 此致 我相信您仍然可以使用Web浏览器任务 http msdn microsoft com
  • ClojureScript 地图查找速度慢

    我有一个简单的地图 def my map 1 2 3 1 1 2 4 5 3 4 2 3 4 5 3 3 5 2 5 6 9 2 1 5 8 3 1 6 我用来执行查找的 然而 这表现得相当差 time doseq x range 500
  • Webpack 长期缓存

    Scenario 我正在尝试使用 webpack 将我的供应商脚本与我的应用程序脚本分开捆绑 尝试1 index js var require lodash console log webpack config js var path re
  • 如何在没有 Django 其余部分的情况下使用 Django 模板?

    我想在我的 Python 代码中使用 Django 模板引擎 但我没有构建基于 Django 的网站 如果没有 settings py 文件 和其他文件 并且必须设置 DJANGO SETTINGS MODULE 环境变量 如何使用它 如果
  • 如何获得 Java 软件商业许可? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我用 Java 编写了一个基于桌面的会计软件 我想放置密钥或许可证或其他类型的安全措施来防止客户端重新分发软件 我只是想知道该怎么办
  • 当对三个整数使用两次 = 运算符时,会发生什么? [复制]

    这个问题在这里已经有答案了 这是做什么的 int x 1 int y 2 int z 3 x y z 我在一些开源项目中遇到过多种此类事情 并且一直对它们感到困惑 我的意思是 运算符在三个整数上使用两次 即x y z 我需要理解这一点 谢谢
  • Visual Studio 无法在 Windows 10 上正确安装

    我将我的笔记本电脑升级到 Windows 10 无预览版 真正的东西 然后我安装了 Visual Studio Community Edition 2015 我已经安装了 VS 2013 这样我就可以开始使用 Cordova 功能 安装过程
  • 使用 p 值的逐步回归删除 p 值不显着的变量

    我想表演一个逐步线性回归 using p values作为选择标准 例如 在每个步骤中删除具有最高即最不显着 p 值的变量 当所有值均由某个阈值定义的显着时停止alpha 我完全知道我应该使用 AIC 例如命令step or stepAIC
  • 获取当前function()作用域的所有变量

    我有问题 我想获取当前的函数范围 我有这个示例代码 我工作正常 function nittle var Pen new Dot Generated dynamical through eval for key in window if wi
  • 使用 Boto3 从 S3 下载文件夹

    Using Boto3 Python SDK 我能够使用该方法下载文件bucket download file 有没有办法下载整个文件夹 Answer recommended by AWS collectives aws Collectiv
  • Python:如何使用 xlwt 编写复数到 Excel?

    我正在尝试使用以下命令将 Python 列表写入 Excel 文件xlwt图书馆 import xlwt from tempfile import TemporaryFile book xlwt Workbook sheet1 book a
  • 调用静态 JNI 方法从 C++ 返回字符串

    我正在尝试在Android中调用以下java方法 public static String getLevelFile String levelName body 从 C 使用以下 jni 代码 JniMethodInfoJavaApi me
  • 调用window.location.href后如何执行脚本?

    我有一个脚本可以将用户重定向到另一个页面 我想在新页面完全加载后将一些内容加载到新页面上的 div 中 我怎样才能做到这一点 以下不起作用 function goToPage window location href http www my
  • 如何在bash中测试变量是否以字符串开头?

    对于固定的前缀长度 我可以这样做 a filename 0 2 a echo temporary emacs file 对于任意前缀如何做到这一点 有更干净的方法吗 s 运算符在右操作数中采用模式 var 123 1234 var
  • 包设置不会传播到分布式的工作人员

    Info julia version julia version 1 6 0 lscpu root MyPackage lscpu Architecture x86 64 CPU op mode s 32 bit 64 bit Byte O
  • 图像具有绝对路径 - 如何在 Laravel Mix 中使用子目录 URL

    我的 Laravel Mix 应用程序将放置在服务器上的子目录中 例如 http localhost pat os server public http localhost pat os server public 我的 vue 组件中的图
  • C# 中 if 语句的性能 [关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 我只是想确定在具有大量迭代的循环中使用每个 if 语句对 C 应用程序性能的影响 我还没有找到与此相关的主题 因此我创建了这个主题 对于测试
  • 如何使用 MOQ 对象测试 Ninject ConstructorArguments?

    我最近一直在做我的第一个测试驱动开发项目 并一直在学习 Ninject 和 MOQ 这是我第一次尝试这一切 我发现 TDD 方法发人深省 Ninject 和 MOQ 也很棒 我正在从事的项目并不是特别适合 Ninject 因为它是一个高度可