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#单元测试在Activator实例化的类上验证非抽象方法_C#_Unit Testing_Abstract_Activator - Fatal编程技术网

C#单元测试在Activator实例化的类上验证非抽象方法

C#单元测试在Activator实例化的类上验证非抽象方法,c#,unit-testing,abstract,activator,C#,Unit Testing,Abstract,Activator,首先,让我向你介绍我的项目 我们正在开发一个应用程序,用户可以在其中使用程序。作为程序,我指的是保密使用的说明清单 有不同类型的程序都继承自程序抽象基类 由于用户可以创建不同类型的程序,我们开发了一个ProgramManager,它可以按程序类型实例化任何类型的程序。我们不需要实例化抽象类,但是所有的具体类(它都可以工作),但是具体的程序都有相同的方法(AddNewChannel,Save,…),我们像程序一样处理它们 下面是一个代码示例: 我所有的具体程序类都经过了单独测试 因此,我想测试是

首先,让我向你介绍我的项目

我们正在开发一个应用程序,用户可以在其中使用程序。作为程序,我指的是保密使用的说明清单

有不同类型的程序都继承自程序抽象基类

由于用户可以创建不同类型的程序,我们开发了一个ProgramManager,它可以按程序类型实例化任何类型的程序。我们不需要实例化抽象类,但是所有的具体类(它都可以工作),但是具体的程序都有相同的方法(AddNewChannel,Save,…),我们像程序一样处理它们

下面是一个代码示例:

我所有的具体程序类都经过了单独测试

因此,我想测试是否调用了以下方法
program.AddNewChannel
program.Save

我查看了Moq,但第一个问题是
Save
方法不是抽象的

此外,使用Activator不允许我进行
模拟

我在单元测试中尝试了以下操作,以尝试实例化模拟并将其像程序一样使用:

    [TestMethod]
    [DataSource("Microsoft.VisualStudio.TestTools.DataSource.XML",
               "|DataDirectory|\\" + DATA_FILE, "Row",
                DataAccessMethod.Sequential)]
    public void CreateProgram_CallsProgramSaveMethod()
    {
        Mock<Program> mock = new Mock<Program>();
        mock.Setup(p => p.AddNewChannel(It.IsAny<int>()));

        Program program = pm.CreateProgram(mock.Object.GetType());
        mock.Verify(p => p.Save());
        mock.Verify(p => p.GetFilePath(It.IsAny<string>()));
        mock.Verify(p => p.AddNewChannel(It.IsAny<int>()), Times.Exactly(ProgramManager.NB_MACHINE_CHANNELS));
        Assert.IsNotNull(program);
        program.DeleteFile();
    }
[TestMethod]
[数据源(“Microsoft.VisualStudio.TestTools.DataSource.XML”,
“|数据目录| \\”+数据文件,“行”,
DataAccessMethod.Sequential)]
public void CreateProgram_CallsProgramSaveMethod()
{
Mock Mock=新Mock();
mock.Setup(p=>p.AddNewChannel(It.IsAny());
Program=pm.CreateProgram(mock.Object.GetType());
mock.Verify(p=>p.Save());
验证(p=>p.GetFilePath(It.IsAny());
mock.Verify(p=>p.AddNewChannel(It.IsAny()),Times.justice(ProgramManager.NB_MACHINE_CHANNELS));
Assert.IsNotNull(程序);
program.DeleteFile();
}
这个问题激发了我们的灵感:

它一直工作到到达行
program.AddNewChannel(i)在for循环中。错误如下:

public abstract class Program 
{
    public bool BaseMethod() {}
}

public class Foo : Program 
{
    public bool CustomFooMethod() {}
}

public class Bar : Program 
{
    public bool CustomBarMethod() {}
}
System.NotImplementedException:'这是DynamicProxy 2错误:拦截器尝试对抽象的方法'Void AddNewChannel(Int32)'进行'处理'。调用抽象方法时,没有要“继续”的实现,拦截器负责模拟实现(设置返回值、输出参数等)

似乎设置不起作用,但我可能理解为什么。(我尝试实例化一个代理的子类型,它没有实现verify方法)

我还尝试在我的程序类上使用代理,该类将实现一个接口,该接口将包含我需要的方法,但这里的问题再次是激活器

有人能给我建议一些测试这些方法调用的方法吗?(即使我需要更改我的方法
CreateProgram

我看了一下这里:但我不确定这是否适用于我的问题

我使用MSTests进行单元测试

注意

其他一切都很好。我的所有其他测试都顺利通过,我的代码似乎正常工作(手工测试)


提前感谢。

问题的根本原因是您正在使用一个类型作为参数,然后使用该参数创建此类型的实例。但是,您正在传入一个抽象类的类型,它不是专门用于实例化的您需要直接使用具体类


因此,我想测试是否调用了以下方法program.AddNewChannel和program.Save

作为一项测试,这还不够。您需要测试这些方法是否按预期工作,而不仅仅是它们是否被调用,然后假设它们工作

您所描述的是(非常基本的)集成测试,而不是单元测试


我不想重复我已经为不同的程序类做的单元测试

这是一个非常危险的决定。单元测试背后的部分思想是为不同的(具体的)对象创建单独的测试。测试需要尽可能合理地隔离。您正在尝试重用测试逻辑,这是一件好事,但它需要以一种不会损害您的测试分离的方式来完成

但是有一些方法可以做到这一点,而又不会影响你的考试成绩。我只有NUnit的测试经验,但我认为类似的方法也适用于其他框架

假设如下:

public abstract class Program 
{
    public bool BaseMethod() {}
}

public class Foo : Program 
{
    public bool CustomFooMethod() {}
}

public class Bar : Program 
{
    public bool CustomBarMethod() {}
}
创建抽象类测试方法:

[TestFixture]
[Ignore]
public class ProgramTests
{
     public virtual Program GetConcrete()
     {
         throw new NotImplementedException();
     }

    [Test]
    public void BaseMethodTestReturnsFalse()
    {
        var result = GetConcrete().BaseMethod();

        Assert.IsFalse(result);
    }
}
[Ignore]
确保
ProgramTests
类不会自行测试

然后从该类继承,在该类中将测试具体类:

[TestFixture]
public class FooTests
{
    private readonly Foo Foo;

    public FooTests()  
    {
        this.Foo = new Foo();
    }

    public overrides Program GetConcrete()
    {
        return this.Foo;
    }

    [Test]
    public void CustomFooMethodTestReturnsFalse()
    {
        var result = this.Foo.CustomFooMethod();

        Assert.IsFalse(result);
    }
}
BarTests
的实现方式类似

NUnit(可能还有其他测试框架)将发现所有继承的测试,并为派生类运行这些测试。因此,从
ProgramTests
派生的每个类都将始终包括
BaseMethodTestReturnsTrue
测试

这样,基类的测试是可重用的,但每个具体类仍将单独测试。这保持了测试分离,同时也防止了必须为每个具体类复制/粘贴测试逻辑


我还注意到:

Mock<Program> mock = new Mock<Program>();
mock.Setup(p => p.AddNewChannel(It.IsAny<int>()));
Program program = pm.CreateProgram(mock.Object.GetType());
就我所见,mock和它的设置都是不相关的,因为您只需要查看它的类型,然后让
CreateProgram()
为您创建一个新对象

其次,这是我测试具体类的例子,你不应该直接使用
Program
进行测试,你应该测试你的派生程序类(
Foo
Bar

这是问题的根本原因。将类型用作参数,然后使用该参数创建此类型的实例。然而,你
Mock<Program> mock = new Mock<Program>();
mock.Setup(p => p.AddNewChannel(It.IsAny<int>()));
Program program = pm.CreateProgram(mock.Object.GetType());
Program program = pm.CreateProgram(typeof(Program).GetType());
public interface IActivatorWrapper
{
    object CreateInstance(Type type);
}

public class ActivatorWrapper : IActivatorWrapper
{
    public object CreateInstance(Type type)
    {
        return Activator.CreateInstance(type);
    }
}