在.net反射中使用mock

本文关键字:mock net 反射 | 更新日期: 2023-09-27 18:19:17

我试图在一些反射上尝试嘲笑(下面的代码)。我已经被建议使用nsubstitute,但我正在努力如何实现这一点,并让它开始。

目前,我的测试存根就像下面这样简单,但是在构建服务器上,这些显然失败了,因为dll不存在。

   [TestMethod]
    public void CanGetStudentXml()
    {
        var student = new ReadStudent();
        var results = student.GetStudentXml();
        Assert.AreNotEqual(string.Empty, results);
    }

谁能给我指点一下我应该怎么做这件事?我需要创建模拟程序集吗?如果是这样,基于下面的问题,我该如何实现呢?

还有,nsubstitute是最适合这份工作的,还是moq更适合?哪一个是最好的mock框架?

示例代码:

namespace MokPoc
{
using System.Reflection;
using System;
using System.Linq;
class Program
{
    static void Main(string[] args)
    {
        var students = new ReadStudent();
        var results = students.GetStudentXml();
        var contacts = students.GetTelephoneXml();
    }
}
public enum ReflectedAssembyType
{
    SimsProcessesTpPersonStudent,
    SimsProcessesTpPersonContact
}
internal class ReflectedAssemblyFactory
{
    public static ReflectedAssemblyBase GetReflectedAssembly(ReflectedAssembyType reflectedAssembyType)
    {
        ReflectedAssemblyBase value = null;
        switch (reflectedAssembyType)
        {
            case ReflectedAssembyType.SimsProcessesTpPersonStudent:
                value = new SimsProcessesTpPersonStudent("ThirdPartyProcesses.dll");
                break;
            case ReflectedAssembyType.SimsProcessesTpPersonContact:
                value = new SimsProcessesTpPersonContact("PersonContacts.dll");
                break;
        }
        return value;
    }
}
internal abstract class ReflectedAssemblyBase
{
    private string path = string.Empty;
    private string type = string.Empty;
    public string Path
    {
        get { return this.path; }
        set { this.path = value; }
    }
    public string Type
    {
        get { return this.type; }
        set { this.type = value; }
    }
    public object InvokeFunction(string name, object[] args)
    {
        var assemblyToLoad = Assembly.LoadFrom(this.path);
        var typeToLoad = assemblyToLoad.GetType(this.type);
        var methodToInvoke = typeToLoad.GetMethod(name, args.Select(o => o.GetType()).ToArray());
        object obj = Activator.CreateInstance(typeToLoad);
        return methodToInvoke.Invoke(obj, args);
    }
}
internal sealed class SimsProcessesTpPersonStudent : ReflectedAssemblyBase
{
    public SimsProcessesTpPersonStudent(string assembly)
    {
        this.Path = System.IO.Path.Combine(@"C:'Program Files'Zoosk", assembly);
        this.Type = "SIMS.Processes.TPPersonStudent";
    }
}
public class ReadStudent 
{
    public string GetStudentXml()
    {
        var contacts = ReflectedAssemblyFactory.GetReflectedAssembly(ReflectedAssembyType.SimsProcessesTpPersonStudent);
        return  (string)contacts.InvokeFunction("GetXmlStudents", new object[] { DateTime.Today });
    }
    public string GetTelephoneXml()
    {
        var contacts = ReflectedAssemblyFactory.GetReflectedAssembly(ReflectedAssembyType.SimsProcessesTpPersonContact);
        return (string)contacts.InvokeFunction("GetXmlTelephone", new object[] { DateTime.Today });
    }
}
}

在.net反射中使用mock

我有重构你的代码理解你试图测试,好像你有很多类的东西看起来可能是一个类的责任,的心在GetStudentAttributes你正在试图做的是,我将创建一个与一个类和公共方法,它返回test.dll一些字符串,然后运行一个实际的方法来测试,在这种情况下,你不使用存根或模仿,但它是一个有效的测试,以确保您的代码工作。你也应该测试GetTelephoneXml和GetStudentXML,但你真正测试的唯一的事情是,GetStudentAttributes是涉及到适当的参数,所以当GetStudentXML被调用你invokeGetStudentAttributes与"ThirdpartyProcesses.dll"answers"GetXmlStudents"。

取决于你使用的解决方案测试框架会不同,Rhynomocks你将不得不做出虚拟允许代理继承和方法调用的方法,但你可以测试参数的方法被称为和你有着什么样子的期盼,我没有用过nSubstitute,所以不知道怎么做,但如果框架是体面的你应该可以测试这些调用和参数。

在使用驱动开发时,你应该做的第一件事就是首先编写测试,确保它失败,让它通过并重构,通常当你试图对现有代码进行测试时,它可能会变得非常困难,有一些关于单元测试的好资源,这是一本很棒的书http://www.amazon.com/Test-Driven-Development-By-Example/dp/0321146530。但根据我的经验,当某些东西很难测试时,它通常告诉你,你的代码太复杂了,或者有些东西可以改进,一旦代码被简化或修复,测试通常不是问题。

祝你好运,希望这对你有所帮助!
using System;
using System.IO;
using System.Linq;
using System.Reflection;
namespace MokPoc
{
    internal class Program
    {
           private static void Main(string[] args)
           {
                var students = new ReadStudentsService();
                string results = students.GetStudentXml();
                string contacts = students.GetTelephoneXml();
           }
    }

    public class ReadStudentsService
    {
        private const string ProgramFilesZooskDirectory = @"C:'Program Files'Zoosk";
        private const string SimsProcessesTppersonstudent = "SIMS.Processes.TPPersonStudent";
        public string GetStudentXml()
        {
            return GetStudentAttributes("ThirdPartyProcesses.dll", "GetXmlStudents");
        }
        public string GetTelephoneXml()
        {
            return GetStudentAttributes("ThirdPartyContacts.dll", "GetXmlTelephone");
        }
        public string GetStudentAttributes(string dllToUse, string methodToExecute)
        {
            var fullpath = Path.Combine(ProgramFilesZooskDirectory, dllToUse);
            var args = new object[] {DateTime.Today};
            var assemblyToLoad = Assembly.LoadFrom(fullpath);
            var typeToLoad = assemblyToLoad.GetType(SimsProcessesTppersonstudent);
            var methodToInvoke = typeToLoad.GetMethod(methodToExecute, args.Select(o => o.GetType()).ToArray());
            var obj = Activator.CreateInstance(typeToLoad);
            return (string) methodToInvoke.Invoke(obj, args);
        }
    }
}