强制测试方法实现数据库接口中定义的所有方法

时间:2013-04-22 08:47:23

标签: c# .net unit-testing design-patterns visual-studio-2012

我正在设计一个能够将DataSource从SQL更改为Oracle和SQLite的解决方案。

为此我使用Unity Framework来实现Lazy Binding。

我创建了一个接口,并将所有数据库方法签名写入其中。

现在我正在为每个数据源编写单独的类(项目)并实现此接口。

我现在想要的是创建一个测试项目,该测试项目应该确保接口中定义的所有方法都必须在测试项目中进行,此测试项目具有单独的测试数据库

是否有任何框架/模式可用于自动强制创建测试方法。

如果有人提供了对方法(当实现接口)编写[TestMethod]属性并将返回类型更改为Void时,我认为这就足够了。

我真正想要的是实现一个测试项目,该项目应该强制为数据库层接口中定义的所有签名创建测试方法。

我使用VS 2012作为开发环境。

如果我没有得到任何现成的解决方案,我如何使用Reflection实现测试项目的方法并在设计时更改其签名。(这是一个奇怪的要求吗?)

如果需要更多详细信息,请与我们联系。

建议是欢迎。

2 个答案:

答案 0 :(得分:1)

我不知道这里有什么特定的模式,但我为这种情况做的是:

  1. 引用接口所在的项目到测试项目
  2. 在CRUDProviderMock.cs或类似的东西中实现接口
  3. 使用模拟类进行测试
  4. 我相信我并不是唯一一个这样做的人,因为我看到很多公司采用这种做法。

    示例项目在这里: https://databaselayertesting.codeplex.com/

    示例项目使用Repository PatternNUnit framework进行测试, 其中:

    1. IRepository是数据库的CRUD接口
    2. EntityOne是示例数据库实体
    3. EntityOneRepositoryMock是使用列表
    4. 的模拟IRepository实现

      您可以使用示例数据库而不是列表来模拟真实的数据库行为。

答案 1 :(得分:0)

我确实意识到这个问题已经过时了,我的解决方案并没有针对VS2012,也没有早期版本的NUnit的限制。但是,我发现你的问题与现代环境完全一样。我也偶然发现了这个问题,并找到了一个合适的解决方案,我认为可能适合其他人,或者我未来的自我,以满足您的要求:

  

我现在想要的是创建一个应该确保的测试项目   必须采用Interface中定义的所有方法......

     

是否有任何框架/模式可供自动强制使用   创建测试方法。

通过将TestCaseSource与适配器模式结合使用,我能够强制接口的任何后续更改都会使程序员也必须更新测试。反对使用反射的美妙之处在于,它将为您提供早期编译时错误,并且通过运行特定测试可以更轻松地跟踪测试错误。

以下代码非常原理图。我自己的用法是将它与特定数据的模拟结合到testObject,并验证是否总是抛出一些特定的异常。一个限制是testObject的设置是共享的,因此最适合简化的场景。

测试代码:

[TestFixture()]
public class SpecificDatabaseTest : IDatabase
{
    private SpecificDatabase testObject = new SpecificDatabase();
    private object TestObject = new object();
    private SomeObject TestSomeObject1 = new SomeObject();
    private SomeObject TestSomeObject2 = new SomeObject();

    public IEnumerable<TestCaseData> SomeMethodData
    {
        get
        {
            yield return new TestCaseData(TestObject).Returns(TestObject);    
        }
    }

    public IEnumerable<TestCaseData> SomeOtherMethodData
    {
        get
        {
            yield return new TestCaseData(TestSomeObject1, TestSomeObject2).Returns(TestSomeObject2);
            yield return new TestCaseData(TestSomeObject2, TestSomeObject1).Returns(TestSomeObject1);
        }
    }

    [Test, TestCaseSource(nameof(SomeMethodData))]
    public object SomeMethod(object data)
    {
        return testObject.SomeMethod(data);
    }

    [Test, TestCaseSource(nameof(SomeOtherMethodData))]
    public SomeObject SomeOtherMethod(SomeObject data1, SomeObject data2)
    {
        return testObject.SomeOtherMethod(data1, data2);
    }
}

其他代码:

public interface IDatabase
{
    object SomeMethod(object data);

    SomeObject SomeOtherMethod(SomeObject data1, SomeObject data2);
}

public class SpecificDatabase : IDatabase
{
    public object SomeMethod(object data)
    {
        return data;
    }

    public SomeObject SomeOtherMethod(SomeObject data1, SomeObject data2)
    {
        return data2;
    }
}

public class SomeObject { }