测试使用预处理器常量的代码

时间:2012-09-25 13:21:46

标签: c# unit-testing

目前我正在对某个项目进行单元测试,除了开发人员使用这样的地方外,一切都很好:

#if USING_EMULATOR
{ do nothing }
#else
{ do a lot of things }
#endif

#if USING_EMULATOR
  return;
#endif
{ do a lot of things }

我认为USING_EMULATOR下的代码是出于调试目的而完成的。有时也出现#if DEBUG。如果现在仅用于调试目的的代码试图执行,我该如何检查实际代码? #undef USING_EMULATOR无济于事。我不太明白预处理器常量,在C#中它们甚至不能只设置定义/未定义所以也许我只是做错了?

3 个答案:

答案 0 :(得分:3)

假设你有一些重构的自由度,你可以将这些指令提取到私有或受保护的属性中,然后给自己一个钩子来修改测试中的值。

您还可以提取IRuntimeConfiguration之类的依赖关系,然后您可以用存根替换测试。

例如:

public class ClassIAmTesting
{
    private readonly IRuntimeConfiguration _runtimeConfig;
    public ClassIAmTesting(IRuntimeConfiguration runtimeConfig)
    {
        _runtimeConfig = runtimeConfig;
    }

    public void MethodIWantToTest()
    {
        if(_runtimeConfig.IsDebug)
            return;

        // …
    }
}

public interface IRuntimeConfiguration
{
    bool IsDebug { get; }
    bool IsUsingEmulator { get; }
}

public class RuntimeConfiguration : IRuntimeConfiguration
{
    public bool IsDebug
    {
        get
        {
            return
#if DEBUG
                true;
#else
                false;
#endif
        }
    }

    // repeat for IsUsingEmulator
}

通过这种方式,运行代码的“选择”不是基于预处理程序指令,而是基于常规bool属性的值。如果替换始终返回IRuntimeConfiguration的其他false实现,即使预处理器值确实已设置,也可以执行代码,就好不在DEBUG而不是USING_EMULATOR中执行。< / p>

答案 1 :(得分:2)

从项目构建设置中的条件编译符号中删除USING_EMULATOR

您还可以使用不同的条件编译符号集创建不同的构建配置。例如。 Debug配置定义DEBUG,而Release不定义。这也意味着如果要执行实际代码,则应运行Release构建,而不是Debug构建。

答案 2 :(得分:1)

棘手的一个。如果您想对#if的两边进行单元测试,则必须进行两次构建 - 一次定义USING_EMULATOR,另一次不定。

这是因为在C#中,当有条件地编译出代码时,它等同于它根本不存在。因此,当(在您的示例中)定义USING_EMULATOR时,它会编译为不同的非等效程序,以便在未定义USING_EMULATOR时。

因此,如果您想对两个“程序”进行单元测试,则需要对两个不同版本的被测软件进行单元测试。

根据您的方案,重新组织软件的某些部分可能是合适的,这样可以根据需要覆盖不同的组件,以根据不同环境的需要更改行为。这样,被覆盖部分的两种实现都存在于每个构建中,并且可以使用适当结构化的单元测试进行测试。