Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/297.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 单元测试:我的ViewModel中使用的模拟静态类_C#_Unit Testing - Fatal编程技术网

C# 单元测试:我的ViewModel中使用的模拟静态类

C# 单元测试:我的ViewModel中使用的模拟静态类,c#,unit-testing,C#,Unit Testing,我在ViewModel中使用静态类(MyStaticClass): public class MyViewModel : ViewModelBase { public string MyProperty { get; set; } //whatever... public void FooMethod() { MyProperty = MyStaticClass.PropertyOne; } } 我的问题是:如何在MyViewMode

我在ViewModel中使用静态类(
MyStaticClass
):

public class MyViewModel : ViewModelBase
{
    public string MyProperty { get; set; }

    //whatever...

    public void FooMethod()
    {
        MyProperty = MyStaticClass.PropertyOne;
    }
}
我的问题是:如何在
MyViewModel
单元测试中模拟
MyStaticClass

我的问题是:如何在MyViewModel单元测试中模拟MyStaticClass

你的问题的答案并不简单:

你不能

一旦你摆脱了代码中的静态垃圾,你可能会把单元测试放回到桌面上。您甚至可以考虑将应用程序的不同类与它们的具体依赖项隔离开来进行单元测试。因此,在单元测试之前,花多一点时间在设计上。是的,当然,您可以在一些高级单元测试框架上花费$$$s,这些框架在运行时会产生一些巫毒魔法,比如用一些编织的代码替换程序集、注入东西等等,但老实说,从长远来看,花一些时间在设计上将是一种更有利可图的方法

但是,在您花费一些时间来适当地思考和设计代码之前,这里有一个可以用来提高代码覆盖率的廉价技巧:

public class MyViewModel : ViewModelBase
{
    internal static Func<string> MyPropertyInjector = () => MyStaticClass.PropertyOne;

    public string MyProperty { get; set; }

    //whatever...

    public void FooMethod()
    {
        this.MyProperty = MyPropertyInjector();
    }
}
但正如我前面所说的,这只是提高代码覆盖率的一个技巧,但您不应该被愚弄到认为这个技巧是在提高代码质量。为此,您可能需要花更多的时间思考和设计

我的问题是:如何在MyViewModel单元测试中模拟MyStaticClass

你的问题的答案并不简单:

你不能

一旦你摆脱了代码中的静态垃圾,你可能会把单元测试放回到桌面上。您甚至可以考虑将应用程序的不同类与它们的具体依赖项隔离开来进行单元测试。因此,在单元测试之前,花多一点时间在设计上。是的,当然,您可以在一些高级单元测试框架上花费$$$s,这些框架在运行时会产生一些巫毒魔法,比如用一些编织的代码替换程序集、注入东西等等,但老实说,从长远来看,花一些时间在设计上将是一种更有利可图的方法

但是,在您花费一些时间来适当地思考和设计代码之前,这里有一个可以用来提高代码覆盖率的廉价技巧:

public class MyViewModel : ViewModelBase
{
    internal static Func<string> MyPropertyInjector = () => MyStaticClass.PropertyOne;

    public string MyProperty { get; set; }

    //whatever...

    public void FooMethod()
    {
        this.MyProperty = MyPropertyInjector();
    }
}

但正如我前面所说的,这只是提高代码覆盖率的一个技巧,但您不应该被愚弄到认为这个技巧是在提高代码质量。为此,您可能需要花更多的时间思考和设计。

您不能模拟静态类。建议避免使用静态类,但在创建确定性函数时除外。e、 你传递这个值,你总是会得到这个值——想想辅助函数之类的


操作数据或依赖某种状态的静态类极难测试。如果没有其他问题,您可以为静态类创建一个包装器,这将有助于缓解一些问题,但是您仍然可能在测试包装器类时遇到问题。

您不能模拟静态类。建议避免使用静态类,但在创建确定性函数时除外。e、 你传递这个值,你总是会得到这个值——想想辅助函数之类的


操作数据或依赖某种状态的静态类极难测试。如果没有其他问题,您可以为静态类创建一个包装器,这将有助于缓解一些问题,但是您仍然可能会在测试包装类时遇到问题。

我完全同意,如果希望进行单元测试,您应该避免使用静态类。但是,如果您对静态类没有选择,那么为了单元测试而控制它的行为是可以做到的(尽管严格来说这不是模仿!)

例如,DateTime类包含非常有用的DateTime.Now静态方法,但在进行单元测试时这是一件非常痛苦的事情,因为“Now”总是在变化。为了解决这个问题,我创建了一个静态类来包装它

public static class SystemTime
{
    private static DateTime _date;

    public static DateTime Now => _date != DateTime.MinValue ? _date : DateTime.Now;

    public static DateTime Today => _date == DateTime.MinValue ? DateTime.Today : _date.Date;

    [Conditional("DEBUG")]
    public static void Set(DateTime date)
    {
        _date = date;
    }

    public static void Reset()
    {
        _date = DateTime.MinValue;
    }
}
这是一个静态类的示例,可以对其进行操作以进行单元测试。在测试类设置方法中,您可以“设置”SystemTime,以便它始终返回您想要的值,从而使调用当前时间的测试代码可测试。您自己的静态类的重要部分是能够将静态类设置为“测试”状态,以便在单元测试中它以一种方式工作,但在发布代码中它的工作方式不同

要做到这一点,您必须添加可以设置为更改代码功能的属性或方法。但是有一个问题,它是静态的,所以一旦设置好,它就保持不变。为了解决这个问题,您必须记住将类恢复到“活动”状态,我会将此代码放在测试类的分解方法中,这样您就不会忘记重置它。另一个问题是,您引入的这些方法和属性可能会被非测试代码调用。为了避免这种情况,您可以设置“DEBUG”属性或将仅测试的方法/属性包装在#if DEBUG块中。这不会阻止您在开发过程中意外设置属性,但会破坏发布版本并标记问题。小心使用这种方法

编辑:


如果我有一个静态类,我不能使其成为非静态类,并且该类比上面的简单示例更重要,那么我将创建一个接口,然后为实现该接口的静态类创建一个包装器,并创建一个也实现该接口的模拟类。我将在构造函数中传入类(我更喜欢)或将其设置为属性。在测试中,通过模拟版本,但在实际实现中通过包装版本。

我完全同意,如果希望进行单元测试,则应避免使用静态类。但是,如果对静态类没有选择,则c