C# 包含逻辑的静态工厂方法的单元测试

C# 包含逻辑的静态工厂方法的单元测试,c#,unit-testing,factory,C#,Unit Testing,Factory,在开始我的问题之前,我想指出,我知道在堆栈溢出方面有很多类似的问题。不幸的是,这些问题都没有帮助我在具体场景中找到一个好的解决方案 问题: public class Db { private XmlMapping mapping; public static Db<T> Create() { var mapping = XmlMapping.Create(typeOf(T).Name); return new Db(mappi

在开始我的问题之前,我想指出,我知道在堆栈溢出方面有很多类似的问题。不幸的是,这些问题都没有帮助我在具体场景中找到一个好的解决方案

问题:

public class Db
{
    private XmlMapping mapping;

    public static Db<T> Create()
    {
        var mapping = XmlMapping.Create(typeOf(T).Name);
        return new Db(mapping);
    }

    private Db(XmlMapping mapping)
    {
        this.mapping = mapping;
    }
}

public class XmlMapping //class under test
{
    public static XmlMapping Create(string filename) //method under test
    {            
        try
        {
            ValidateFilename(filename);
            //deserialize xml to object of type XmlMapping
            var result = Deserialize(filename);
            if (result.IsInValid())
                throw Exception()
            return result; 
        }
        catch (Exception)
        {
            throw new DbException();
        }
    }
}
public class XmlMapping : IMapping //class under test
{
    internal static Func<Type, IMapping> DeserializeHandler { get; set; }

    static XmlMapping()
    {
        DeserializeHandler = DeserializeMappingFor;
    }

    public static IMapping Create(Type type)
    {
        try
        {
            var mapping = DeserializeHandler(type);
            if (!mapping.IsValid())
                throw new InvalidMappingException();
            return mapping;
        }
        catch (Exception ex)
        {
            throw new DataException("Failed to load mapping configuration from xml file.", ex);
        }
    }

    internal XmlMapping(IMapping mapping)
    {
        this.Query = mapping.Query;
        this.Table = mapping.Table;
        this.Entity = mapping.Entity;
        this.PropertyFieldCollection = mapping.PropertyFieldCollection;
    }

    private XmlMapping() { }
}


[TestClass]
public class MappingTests //testing class
{
    [TestMethod]
    public void Create_ValidDeserialization_ReturnsObjectInstance()
    {
        XmlMapping.DeserializeHandler = MakeFakeHandlerFor(MakeMappingStub());
        var result = XmlMapping.Create(typeof(ActivityDto));
        Assert.IsInstanceOfType(result, typeof(XmlMapping));
    }
}
我想为包含逻辑的静态工厂方法编写一个单元测试。我正在寻找一种方法来单元测试这个方法,即使它是静态的。如果这是不可能的,也许有人可以指出一个更好的设计,为我的类测试。我也考虑过使用IoC,但考虑到单元测试,我看不出它的优势

代码:

public class Db
{
    private XmlMapping mapping;

    public static Db<T> Create()
    {
        var mapping = XmlMapping.Create(typeOf(T).Name);
        return new Db(mapping);
    }

    private Db(XmlMapping mapping)
    {
        this.mapping = mapping;
    }
}

public class XmlMapping //class under test
{
    public static XmlMapping Create(string filename) //method under test
    {            
        try
        {
            ValidateFilename(filename);
            //deserialize xml to object of type XmlMapping
            var result = Deserialize(filename);
            if (result.IsInValid())
                throw Exception()
            return result; 
        }
        catch (Exception)
        {
            throw new DbException();
        }
    }
}
public class XmlMapping : IMapping //class under test
{
    internal static Func<Type, IMapping> DeserializeHandler { get; set; }

    static XmlMapping()
    {
        DeserializeHandler = DeserializeMappingFor;
    }

    public static IMapping Create(Type type)
    {
        try
        {
            var mapping = DeserializeHandler(type);
            if (!mapping.IsValid())
                throw new InvalidMappingException();
            return mapping;
        }
        catch (Exception ex)
        {
            throw new DataException("Failed to load mapping configuration from xml file.", ex);
        }
    }

    internal XmlMapping(IMapping mapping)
    {
        this.Query = mapping.Query;
        this.Table = mapping.Table;
        this.Entity = mapping.Entity;
        this.PropertyFieldCollection = mapping.PropertyFieldCollection;
    }

    private XmlMapping() { }
}


[TestClass]
public class MappingTests //testing class
{
    [TestMethod]
    public void Create_ValidDeserialization_ReturnsObjectInstance()
    {
        XmlMapping.DeserializeHandler = MakeFakeHandlerFor(MakeMappingStub());
        var result = XmlMapping.Create(typeof(ActivityDto));
        Assert.IsInstanceOfType(result, typeof(XmlMapping));
    }
}
公共类数据库
{
私有xml映射;
公共静态数据库Create()
{
var-mapping=XmlMapping.Create(typeOf(T).Name);
返回新的数据库(映射);
}
私有数据库(XmlMapping)
{
this.mapping=映射;
}
}
公共类XmlMapping//测试中的类
{
公共静态XmlMapping Create(字符串文件名)//测试中的方法
{            
尝试
{
ValidateFilename(文件名);
//将xml反序列化为XmlMapping类型的对象
var result=反序列化(文件名);
if(result.IsInValid())
抛出异常()
返回结果;
}
捕获(例外)
{
抛出新的DbException();
}
}
}
我想要单元测试的方法创建在类XmlMapping中。此方法序列化xml文件并生成XmlMapping类型的对象。我试图为序列化部分编写一个存根。但是不想在构造函数中使用映射类调用我的数据库工厂(构造函数注入)

编辑:

public class Db
{
    private XmlMapping mapping;

    public static Db<T> Create()
    {
        var mapping = XmlMapping.Create(typeOf(T).Name);
        return new Db(mapping);
    }

    private Db(XmlMapping mapping)
    {
        this.mapping = mapping;
    }
}

public class XmlMapping //class under test
{
    public static XmlMapping Create(string filename) //method under test
    {            
        try
        {
            ValidateFilename(filename);
            //deserialize xml to object of type XmlMapping
            var result = Deserialize(filename);
            if (result.IsInValid())
                throw Exception()
            return result; 
        }
        catch (Exception)
        {
            throw new DbException();
        }
    }
}
public class XmlMapping : IMapping //class under test
{
    internal static Func<Type, IMapping> DeserializeHandler { get; set; }

    static XmlMapping()
    {
        DeserializeHandler = DeserializeMappingFor;
    }

    public static IMapping Create(Type type)
    {
        try
        {
            var mapping = DeserializeHandler(type);
            if (!mapping.IsValid())
                throw new InvalidMappingException();
            return mapping;
        }
        catch (Exception ex)
        {
            throw new DataException("Failed to load mapping configuration from xml file.", ex);
        }
    }

    internal XmlMapping(IMapping mapping)
    {
        this.Query = mapping.Query;
        this.Table = mapping.Table;
        this.Entity = mapping.Entity;
        this.PropertyFieldCollection = mapping.PropertyFieldCollection;
    }

    private XmlMapping() { }
}


[TestClass]
public class MappingTests //testing class
{
    [TestMethod]
    public void Create_ValidDeserialization_ReturnsObjectInstance()
    {
        XmlMapping.DeserializeHandler = MakeFakeHandlerFor(MakeMappingStub());
        var result = XmlMapping.Create(typeof(ActivityDto));
        Assert.IsInstanceOfType(result, typeof(XmlMapping));
    }
}
我的数据库工厂是通用的。泛型类型用于确定哪个xml文件应该被放大,即:typeOf(T)=Customer-->XmlMapping file=Customer.xml

解决方案(谢谢Jeff!):

public class Db
{
    private XmlMapping mapping;

    public static Db<T> Create()
    {
        var mapping = XmlMapping.Create(typeOf(T).Name);
        return new Db(mapping);
    }

    private Db(XmlMapping mapping)
    {
        this.mapping = mapping;
    }
}

public class XmlMapping //class under test
{
    public static XmlMapping Create(string filename) //method under test
    {            
        try
        {
            ValidateFilename(filename);
            //deserialize xml to object of type XmlMapping
            var result = Deserialize(filename);
            if (result.IsInValid())
                throw Exception()
            return result; 
        }
        catch (Exception)
        {
            throw new DbException();
        }
    }
}
public class XmlMapping : IMapping //class under test
{
    internal static Func<Type, IMapping> DeserializeHandler { get; set; }

    static XmlMapping()
    {
        DeserializeHandler = DeserializeMappingFor;
    }

    public static IMapping Create(Type type)
    {
        try
        {
            var mapping = DeserializeHandler(type);
            if (!mapping.IsValid())
                throw new InvalidMappingException();
            return mapping;
        }
        catch (Exception ex)
        {
            throw new DataException("Failed to load mapping configuration from xml file.", ex);
        }
    }

    internal XmlMapping(IMapping mapping)
    {
        this.Query = mapping.Query;
        this.Table = mapping.Table;
        this.Entity = mapping.Entity;
        this.PropertyFieldCollection = mapping.PropertyFieldCollection;
    }

    private XmlMapping() { }
}


[TestClass]
public class MappingTests //testing class
{
    [TestMethod]
    public void Create_ValidDeserialization_ReturnsObjectInstance()
    {
        XmlMapping.DeserializeHandler = MakeFakeHandlerFor(MakeMappingStub());
        var result = XmlMapping.Create(typeof(ActivityDto));
        Assert.IsInstanceOfType(result, typeof(XmlMapping));
    }
}
公共类XmlMapping:IMapping//测试中的类
{
内部静态Func反序列化处理程序{get;set;}
静态XmlMapping()
{
DeserializeHandler=DeserializeMappingFor;
}
公共静态映像创建(类型)
{
尝试
{
变量映射=反序列化处理程序(类型);
如果(!mapping.IsValid())
抛出新的InvalidMappingException();
回归映射;
}
捕获(例外情况除外)
{
抛出新的DataException(“未能从xml文件加载映射配置。”,ex);
}
}
内部XmlMapping(IMapping映射)
{
this.Query=mapping.Query;
this.Table=mapping.Table;
this.Entity=mapping.Entity;
this.PropertyFieldCollection=mapping.PropertyFieldCollection;
}
私有XmlMapping(){}
}
[测试类]
公共类映射测试//测试类
{
[测试方法]
public void Create_ValidDeserialization_ReturnsObjectInstance()
{
XmlMapping.DeserializeHandler=MakeFakeHandlerFor(MakeMappingStub());
var result=XmlMapping.Create(typeof(ActivityDto));
IsInstanceOfType(result,typeof(XmlMapping));
}
}

我将使用伪操作处理程序来帮助验证反序列化调用的内容。让我们添加一个Func委托属性,并将其默认值添加到serialize方法中。您的XmlMapping类和测试类似于:

public class XmlMapping //class under test
{

    static XmlMapping()
    {
        // Default the handler to the normal call to Deserialize
        DeserializeHandler = Deserialize;
    }

    public static XmlMapping Create(string filename) //method under test
    {
        //deserialize xml to object of type XmlMapping
        //preudocode:
        var result = DeserializeHandler(string.Format("{0}.xml",filename));
        //...
        return result;
    }

    // Abstract indirection function to allow you to swap out Deserialize implementations
    internal static Func<string, XmlMapping> DeserializeHandler { get; set; }

    private static XmlMapping Deserialize(string fileName)
    {
        return new XmlMapping();
    }

}

public class CreateTests {

    public void CallingDeserializeProperly()
    {

        // Arrange
        var called = false;
        Func<string, XmlMapping> fakeHandler = (string f) =>
        {
            called = true; // do your test of the input and put your result here
            return new XmlMapping();
        };

        // Act
        XmlMapping.DeserializeHandler = fakeHandler;
        var m = XmlMapping.Create("test");

        // Assert
        Assert.IsTrue(called);

    }

}
公共类XmlMapping//测试中的类
{
静态XmlMapping()
{
//默认处理程序为反序列化的正常调用
反序列化处理程序=反序列化;
}
公共静态XmlMapping Create(字符串文件名)//测试中的方法
{
//将xml反序列化为XmlMapping类型的对象
//预udocode:
var result=反序列化处理程序(string.Format(“{0}.xml”,文件名));
//...
返回结果;
}
//抽象间接函数,用于交换反序列化实现
内部静态Func反序列化处理程序{get;set;}
私有静态XmlMapping反序列化(字符串文件名)
{
返回新的XmlMapping();
}
}
公共类测试{
public void callingdeserializeproperty()
{
//安排
var=false;
Func fakeHandler=(字符串f)=>
{
called=true;//对输入进行测试并将结果放在这里
返回新的XmlMapping();
};
//表演
XmlMapping.DeserializeHandler=fakeHandler;
var m=XmlMapping.Create(“test”);
//断言
Assert.IsTrue(称为Assert.IsTrue);
}
}

您如何向XmlMapping类传递要反序列化的Xml文件?啊,我忘了这一部分。。。我将编辑我的问题,因此,您正在尝试验证是否使用正确的参数调用“反序列化”?我进行参数验证,反序列化对象并检查反序列化是否成功。四周都是试捕。嘿,杰夫,这看起来很有趣!我明天就试试看。谢谢你的努力。我很感激。如果您还有任何需要单元测试帮助的地方,请给我打电话-我是推特上的@csharpfritz这里是龙!在这里,当测试Db.Create()时,您必须模拟一些其他隐藏的依赖项(XmlMapping),这似乎很奇怪,但如果您检查Db的代码,这似乎是无辜的。但是,调用层次结构上的所有后续对象也需要模拟此依赖关系。这不是一个滑坡,这是一个悬崖。未来的所有测试都将是脆弱和难以理解的。使用工厂@布莱恩:你是如何设计这个课程的?我已经在使用工厂方法了,那么为什么独立工厂更适合这个目的呢?您的工厂方法是该类型的静态成员,所以在使用该类型的任何地方都可以使用工厂——这就引出了使用