【问题标题】:Can't access information from configuration files when tests have host type "Moles"当测试的主机类型为“Moles”时,无法访问配置文件中的信息
【发布时间】:2012-02-25 09:32:53
【问题描述】:

当单元测试的主机类型为“Moles”时,我们在通过单元测试访问 .net 配置文件(例如 app.config 和 web.config)中的信息时遇到问题。这引起了很多头痛,所以我希望有人知道可以做什么。

我们使用的是 Visual Studio 2010,我相信我们已经在安装了 VS 2010 SP1 的机器和未安装 SP1 的机器上进行了尝试,并在 32 位和 64 位机器上进行了尝试。

我冒昧地将测试简化为最简单的术语。可以通过编写由以下两个文件组成的单元测试项目并在取消注释唯一的注释行后运行测试来重新创建该问题。该测试在没有主机类型的情况下工作,但是当您将 Moles 作为主机类型引入时,测试中的 null 断言会失败。我们不确定为什么。

一、配置文件App.config:

<?xml version="1.0"?>
<configuration>
  <connectionStrings>
    <add name="Connection" connectionString="Something" />
  </connectionStrings>
</configuration>

接下来是包含单个测试的测试类:

namespace TestProject
    {
    using System.Configuration;
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    [TestClass]
    public class UnitTest
        {

        [TestMethod]
        //[HostType("Moles")]
        public void TestMethod()
            {
            var data = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            Assert.IsNotNull(data.ConnectionStrings.ConnectionStrings["Connection"]);
            }

        }

    }

如果有人能提供任何见解,我将不胜感激。

非常感谢,

尼克

【问题讨论】:

标签: c# moles pex pex-and-moles


【解决方案1】:

我不确定它是否能完成这项工作,但您可以尝试以下解决方法:使用文件映射打开配置。 代码将如下所示:

ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
fileMap.ExeConfigFilename = configurationFilePath;
System.Configuration.Configuration configuration =
    ConfigurationManager.OpenMappedExeConfiguration(
        fileMap,
        ConfigurationUserLevel.None);

【讨论】:

    【解决方案2】:

    任何时候执行单元测试,应用程序和用户设置都应该通过依赖注入传递。这是通过为设置创建一个存根来完成的,这很容易做到。

    1. 在正在测试的项目中创建一个接口,其中包含每个配置设置的属性。让我们称之为“ISettings”以供参考。

    2. 在实现接口的目标程序集中创建一个存根(类)。存根中的每个属性都应该只包含一个从配置文件返回相应设置的 get。我们将此存根称为“SettingsStub”。此存根由目标程序集在生产环境中使用。

    3. 将 ISettings 类型化参数添加到目标类型(正在测试的类)构造函数。目标类中的字段必须设置为传递给构造函数的 ISettings 对象。根据某些设计模式(MVVM 等)的要求,您可以创建重载构造函数并保留默认构造函数。默认构造函数(没有参数的构造函数)可以简单地实例化一个新的 SettingsStub,用于生产。 测试必须始终使用重载的构造函数!

    4. 为测试项目创建一个设置存根,该存根也实现了 ISettings。我们将其称为 TestSettingsStub。此存根包含大多数测试都可接受的硬编码值。

    5. 重建目标和测试项目。 Moles 生成一个名为 SISettings 的 Stub 类型。

    当您不需要调整任何设置值时,请使用具体的 TestSryingsStub。或者,当需要为一两个测试调整值时,使用 Miles Stub 类型。 Moles Stub 类型的目的是避免制作包含一两个独特更改的许多存根。

    在调用重载构造函数时,可以互换使用 SettingsStub、TestSettigsStub 和 SISettings 类型。现在,您可以完全控制在每个上下文中使用的设置,而无需在测试期间切换逻辑或手动更改设置值。目标代码只是从本地字段中检索设置值,而不是直接从配置文件中检索。请参阅依赖注入和控制反转 (IOC) 主题。

    和往常一样,为了安全起见,您的开发工作站开发无法访问生产网络上的外部依赖系统(数据库等)!

    编码愉快!

    【讨论】:

    • 投反对票,因为虽然第 1 点很好,但除此之外的任何东西都不是。 Moles 对于这种方法来说是多余的,并且无论如何都不是它的意图。在这种情况下,一个简单的模拟框架(例如 Moq)就足够了。 Moles 应该用于您不能模拟的代码,例如文件系统访问、数据库调用等……在单元测试而不是集成测试中进行。
    • @dotnetnate 我不提倡在简单的依赖注入案例中使用模拟框架。但是,使用已在使用的模拟框架的存根功能并没有错。
    • @dotnetnate 我不明白在测试中使用 Moles 是多么糟糕的选择。毕竟,它是一个模拟和存根框架。我什至会说使用起订量更容易,特别是对于小型项目;因为,通过单个 lambda 编写绕道比构建 Moq 对象更快,并且达到相同的目的。当一个人已经使用 Moles 时,为什么还要使用 Moq,因为它们都做同样的工作?
    • 如果是您可以控制的代码,这是一个可怕的选择。配置并将其注入类是您可以控制的。模拟文件系统访问是您没有可以控制的事情,并且是 Moles 适合的地方。如果您将 Moles 用于您编写的任何代码,则表明设计不佳。
    • @dotnetnate 哦!非常好的评论。上票!!我要把它弄成青铜,挂在我的办公室里,让后辈们每天都能看到。 (说真的!)
    【解决方案3】:

    我同意 Mike 的回答在逻辑上是正确的(即您没有将配置加载与类分开 - 可能),实际问题是对于 Moles 主机类型,根据您的原始问题,您需要Mole 对配置系统的调用,例如

     MConfigurationManager.AllInstances.OpenExeConfiguration (... finish your moleing here...)
    

    语法是近似的——我不记得在这种情况下你最终是 SConfigurationManager 还是 MConfigurationManager。

    我完全不同意 Mike 的观点是,“...开发工作站无法访问外部依赖系统...”的说法完全是可怕的建议。我们将这些东西称为集成测试。

    是的,您作为开发人员应该创建它们。在某些时候,您将编写涉及具体实现的代码(例如,数据库、支持服务等),如果您没有测试该交互,那么您就大错特错了。

    【讨论】:

    • 单元测试应该只测试目标代码,没有别的。集成测试当然应该测试与其他代码和外部资源的交互(我不是白痴)。我的印象是这是一个关于单元测试的问题,而不是集成测试。如果这是一个单元测试的问题,那么你的将是“完全可怕的建议”。单元测试和集成测试是相互排斥的。此外,当你同样有能力提出糟糕的建议时,没有必要击落别人。
    • 请阅读我的回复。看来我们都需要更仔细地阅读彼此的内容。我明确区分了单元测试和集成测试。我的错误是在阅读您建议的“...生产网络”部分。很大程度上与对话无关,并且可能是一个超载的术语,但我会冒昧地假设您只是针对生产 SOR。
    • 我同意。上下文对程序员之间的交流是一种相当狡猾的损害。打的好。我向你致敬,好先生。
    猜你喜欢
    • 2012-11-10
    • 1970-01-01
    • 1970-01-01
    • 2018-04-28
    • 2011-05-05
    • 1970-01-01
    • 2018-08-26
    • 2021-08-15
    • 1970-01-01
    相关资源
    最近更新 更多