N层架构中的单元测试

时间:2014-09-30 07:49:10

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

我想为其他人编写的程序编写测试。但是在编写测​​试时我遇到了一些问题。我无法准确理解如何伪造一些物体。我搜索并找到了Unit Test for n tier architecture,但它对我没有帮助。例如,我想为下面的代码编写一个测试(我知道这是一个虚拟代码,只是为了澄清)

        public List<CustomerObject> FetchCustomersByName(CustomerObject obj)
        {
            DAL customerDal = new DAL();
            //Maybe other operations
            List<CustomerObject> list = customerDal.FetchByName(obj.Name);
            //Maybe other operations over list
            return list;
        }

我只想测试FetchCustomersByName但是与DAL有连接。我认为创建存根类但在这种情况下我必须更改我的原始代码。它由其他人编码。我该如何为这种方法编写测试?

提前致谢。

2 个答案:

答案 0 :(得分:1)

不要对数据访问层进行单元测试。为它编写集成测试。

在DAL中模拟依赖项并不值得给它带来麻烦,因为它不能保证任何东西。

如果你考虑一下,DAL依赖于SQL方言和数据库模式。因此,您的单元测试可能会正常工作。但是当你运行真正的解决方案时,它仍然会失败。原因可能是您的SQL查询不正确或者其中一个类属性类型与表列类型不匹配。

单元测试通常是针对业务逻辑编写的。他们捕获的一件事是不会产生异常的错误,例如错误的条件或计算错误。

<强>更新

确定。所以你的例子实际上包含业务逻辑。方法名称欺骗了我。

您必须更改创建DAL类的方式。但你不必像杰克休斯所说的那样使用构造函数注入。相反,您可以使用工厂模式:

    public List<CustomerObject> FetchCustomersByName(CustomerObject obj)
    {
        var customerDal = DalFactory.Create<CustomerDal>();

        //Maybe other operations
        List<CustomerObject> list = customerDal.FetchByName(obj.Name);
        //Maybe other operations over list
        return list;
    }

这更简单,因为现在您可以使用“全部替换”将所有var customerDal = new CustomerDal()更改为var customerDal = DalFactory.Create<CustomerDal>();

在该工厂类中,您可以调用不同的实现

public class DalFactory
{
    public static IDalFactory Factory { get set; }

    static DalFactory()
    {
        Factory = new DefaultDalFactory();
    }


    public static T Create<T>() where T : class
    {
        return Factory.Create<T>();
    }
}

public interface IDalFactory
{
    T Create<T>() where T : class
}

public class DefaultDalFactory : IDalFactory
{
    public T Create<T>() where T : class
    {
        return new T();
    }
}

代码不漂亮,但它以最小的重构解决了你的问题。我建议你从那开始,然后尝试改变你的编码标准,以便允许构造函数注入。

要在测试中使用它,您可以使用以下实现。它使用[ThreadStatic]允许多个测试同时运行。

public class TestDalFactory : IDalFactory
{
    [ThreadStatic]
    private static Dictionary<Type, object> _instances;

    public static Dictionary<Type, object> DalInstances
    {
        get
        {
            if (_instances == null)
                _instances = new Dictionary<Type, Object>();
            return _instances;
        }
   }

    public static TestDalFactory Instance = new TestDalFactory();

    public T Create<T>() where T : class
    {
        return (T)_instances[typeof(T)];
    }
}

接下来,在测试中,您可以通过执行以下操作配置DAL工厂以返回模拟:

[TestClass]
public class MyBusinessTests
{
    [TestInitialize]
    public void Init()
    {
        DalFactory.Instance = TestDalFactory.Instance;
    }

    [TestMethod]
    public void do_some_testing_in_the_business()
    {
        TestDalFactory.Instance.DalInstances[typeof(CustomerDal)] = new MyNewMock();

        //do the testing here
    }
}

答案 1 :(得分:1)

使用构造函数注入DAL将允许您存根DAL层。理想情况下,您将注入一个接口。使用我使用的工具来模拟具体类是有点痛苦的。商业模拟工具可能更适合模拟具体类,但我没有使用任何这些。

class YourClass
{
    private DAL customerDal;

    public YourClass(DAL theDal)
    {
        customerDal = theDal;
    }

    public List<CustomerObject> FetchCustomersByName(CustomerObject obj)
    {
       // don't create the DAL here...
       //Maybe other operations
       List<CustomerObject> list = customerDal.FetchByName(obj.Name);
       //Maybe other operations over list
       return list;
     }
}

[Test]
public void TestMethodHere()
{
    // Arrange
    var dalMock = Mock.Of<DAL>();
    // setup your mock DAL layer here... need to provide data for the FetchByName method
    var sut = new YourClass(dalMock);

    // Act
    var actualResult = sut.FetchCustomersByName(new CustomerObject());

    // Assert
    // Your assert here...
}