代码之家  ›  专栏  ›  技术社区  ›  Cornelius

从使用泛型的类型继承的单元测试

  •  1
  • Cornelius  · 技术社区  · 16 年前

    我有一个与一些类实现的泛型的接口。对于这些类中的每一个,都有代理类来实现接口。大致给出以下代码:

    public interface ISomeInterface<T>
    {
        T SomeProperty
        {
            get;
        }
    
        T SomeAction();
    }
    
    public interface IClassA : ISomeInterface<string>
    {
        void Action();
    }
    
    
    public class ClassA : IClassA
    {
        // Code goes here
    }
    
    public class ClassAProxy : IClassA
    {
        // Code goes here
    }
    

    单元测试代码我希望如下所示:

    public abstract class ISomeInterfaceTests<T>
    {
        [TestMethod()]
        public void SomePropertyTest()
        {
            ISomeInterface<T> target;
            ISomeInterface<T> oracle;
            this.CreateInstance(out target, out oracle);
    
            Assert.AreEqual(oracle.SomeProperty, target.SomeProperty);
        }
    
        [TestMethod()]
        public void SomeActionTest()
        {
            ISomeInterface<T> target;
            ISomeInterface<T> oracle;
            this.CreateInstance(out target, out oracle);
    
            T oracleValue = oracle.SomeAction();
            T targetValue = target.SomeAction();
    
            Assert.AreEqual(oracleValue, targetValue);
        }
    
        // More tests
    
        protected abstract void CreateInstance(out ISomeInterface<T> target, out ISomeInterface<T> oracle);
    }
    
    [TestClass()]
    public class ClassAProxyTests : ISomeInterfaceTests<string>
    {
        // ClassAProxy specific tests
    
        protected override void CreateInstance(out ISomeInterface<string> target, out ISomeInterface<string> oracle)
        {
            // Create target as ClassAProxy here and oracle as ClassA
        }
    }
    

    但这就产生了错误: UTA002:不能在泛型类IsomeInterfaceTests上定义TestClass属性<t>。

    有什么好的解决办法吗?目前,我能想到的最佳解决方案是在ClassApproxyTests中有一个方法,它调用isomeInterfaceTests中的不同测试方法<t>。不过,这种方法有几个问题:

    • 对于每个实现isomeInterfacetests的测试,都必须手动完成。
    • 如果一个方法导致断言失败,则不会执行其余的方法。
    • 不能使用ExpectedException属性,必须将所需代码包装在Try-Catch语句中。

    但遗憾的是,我没有找到更好的解决办法。

    2 回复  |  直到 14 年前
        1
  •  1
  •   Steve Guidi    16 年前

    听起来你需要使用 GenericTestFixture 特点 NUnit 2.5。此功能允许您将 [TestFixture] 属性,然后指定应用测试夹具的哪些专门化。

    您的主要测试夹具将如下所示(您也可以删除一些接口):

    [TestFixture(typeof(string))]
    public class ClassAProxyTests<T> : ISomeInterfaceTests<T> where T: class
    {
        // Add ISomeInterfaceTests<T> methods here.
        // ISomeInterfaceTests may no longer be required as the abstraction is defined in ClassAProxyTests.
    
        // ClassAProxy specific tests
    
        protected override void CreateInstance(out ISomeInterface<T> target, out ISomeInterface<string> oracle)
        {
            // Create target as ClassAProxy here and oracle as ClassA
        }
    }
    
        2
  •  0
  •   Randolpho    16 年前

    您拥有父类的唯一原因是创建接口的实例,是吗?

    使用 MOQ 相反。

    编辑:

    不完全是。isomeInterfacests<t>类用于测试实现isomeInterface<t>接口的代理的功能-它根据代理对象(Oracle)测试代理。 科尼利厄斯

    隐马尔可夫模型。。。听起来像是集成测试。您的Oracle对象是以某种方式从数据库中读取的,还是像您应该的那样嘲笑它们?不管怎样,我支持使用moq来获取您的实例,并大致模拟与集成测试。

    但让我吃惊的是,您的测试泛化方法可能是问题所在。也许是另一种方法?试试看:

    public static class GenericISomeInterfaceTests
    {
        public static void SomePropertyTest<T>(ISomeInterface<T> target, ISomeInterface<T> oracle)
        {
    
            Assert.AreEqual(oracle.SomeProperty, target.SomeProperty);
        }
    
        public static void SomeActionTest<T>(ISomeInterface<T> target, ISomeInterface<T> oracle)
        {
    
            T oracleValue = oracle.SomeAction();
            T targetValue = target.SomeAction();
    
            Assert.AreEqual(oracleValue, targetValue);
        }
    
        // More tests
    }
    
    [TestClass()]
    public class ClassAProxyTests
    {
        [TestMethod]
        public void SomePropertyStringTest()
        {
            // set up instances (using MOQ, or whatever) with the string generic type. 
            // Call them target and oracle
    
            // then call your generic test methods
            GenericISomeInterfaceTests.SomePropertyTest<string>(target, oracle);
        }
    
        [TestMethod]
        public void SomeActionStringTest()
        {
            // set up instances (using MOQ, or whatever) with the string generic type. 
            // Call them target and oracle
    
            // then call your generic test methods
            GenericISomeInterfaceTests.SomeActionTest<string>(target, oracle);
        }
    }