如何调用重载方法代替实际方法

时间:2013-08-08 00:22:56

标签: c# .net mocking nmock

我有一个Mocking.sln,它有两个项目:Student(类库)和StudentStat(控制台应用程序)

Student项目详情如下:

    private static Dictionary<int, int> GetStudentData()
        {
            // Key: Student ID Value: Total marks(marks in math + marks in physics)
            Dictionary<int, int> studentResultDict = new Dictionary<int, int>();

            using (SqlConnection con = new SqlConnection("Data Source=.;Initial Catalog=myDB;Integrated Security=true"))
            {
                con.Open();
                string cmdStr = "Select * from Student";
                using (SqlCommand cmd = new SqlCommand(cmdStr, con))
                {
                    using (SqlDataReader reader = cmd.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            studentResultDict.Add((int)reader["ID"], (int)reader["MarksInMath"] + (int)reader["MarksInPhysics"]);
                        }
                    }
                }
            }

            return studentResultDict;
        }

     public static void CalculateTotalMarks()
        {
            Dictionary<int, int> studentResultDict = GetStudentData();
            foreach (var item in studentResultDict)
            {
                Console.WriteLine("{0}\t{1}", item.Key, item.Value);
            }
        }

StudentStat项目详情如下:

class Program
    {
        static void Main(string[] args)
        {
            StudentInfo.CalculateTotalMarks();
        }
    }

GetStudentData()方法从DB和输出详细信息中读取详细信息。假设这是我的生产代码,我无权更改任何内容。

我有一个GetStudentData()的重载版本,它将filePath作为参数并从文本文件中读取详细信息。以下是方法:

private static Dictionary<int, int> GetStudentData(string filepath)
    {
        Dictionary<int, int> studentResultDict = new Dictionary<int, int>();
        foreach (var item in File.ReadAllLines(filepath))
        {
            string[] data = item.Split(new string[] { "|" }, StringSplitOptions.RemoveEmptyEntries);
            studentResultDict.Add(Convert.ToInt32(data[0]), Convert.ToInt32(data[1]) + Convert.ToInt32(data[2]));
        }

        return studentResultDict;
    }

现在当我在StudentInfo.CalculateTotalMarks()中调用StudentStat.exe时,我希望调用此重载GetStudentData(string filepath)而不是其他方法(从DB读取数据),并显示输出。< / p>

我听说使用NMock3可以实现这一点。但我对此一无所知。你能否分享一下代码样本..这也有助于我学习NMock3。任何帮助表示赞赏...

1 个答案:

答案 0 :(得分:0)

你可以使用Test driven developement你需要做的就是重构你所拥有的代码并实现属于SOLID Principle的接口隔离,我建议你阅读{{ 3}}这是TDD的父亲,我只是通过阅读一本关于单元测试艺术的书来学习TDD(它现在可能已经老了)但是简而言之,你需要做的就是将代码分离并分离你的实现,只需为它定义合同。

例如,您可以使用此接口来定义您需要执行的操作的方法。

interface IStudentService{
   Dictionary<int, int> GetStudentData() 
}

然后你可以有两个不同的实现

为了简单起见,我只是复制并粘贴您的SQL代码,但您必须记住,在TDD方法中,SQL命令也需要被视为依赖项。

public class DBStudentService:IStudentService{

    public Dictionary<int, int> GetStudentData()
    {
    // Key: Student ID Value: Total marks(marks in math + marks in physics)
        Dictionary<int, int> studentResultDict = new Dictionary<int, int>();
        using (SqlConnection con = new SqlConnection("Data Source=.;Initial Catalog=myDB;Integrated Security=true"))
            {
                con.Open();
                string cmdStr = "Select * from Student";
                using (SqlCommand cmd = new SqlCommand(cmdStr, con))
                {
                    using (SqlDataReader reader = cmd.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            studentResultDict.Add((int)reader["ID"], (int)reader["MarksInMath"] + (int)reader["MarksInPhysics"]);
                        }
                    }
                }
            }

            return studentResultDict;
        }
}

然后创建一个不同的实现,假设

   public class FileStudentService:IStudentService{
        steing _filepath;
        Public FileStudentService(string filepath){
          _filepath = filepath;
        }

        public Dictionary<int, int> GetStudentData()
        {
            Dictionary<int, int> studentResultDict = new Dictionary<int, int>();
            foreach (var item in File.ReadAllLines(_filepath))
            {
                string[] data = item.Split(new string[] { "|" }, StringSplitOptions.RemoveEmptyEntries);
                studentResultDict.Add(Convert.ToInt32(data[0]), Convert.ToInt32(data[1]) + Convert.ToInt32(data[2]));
            }

        return studentResultDict;
        }

    }

注意你的方法不再是静态的,因为它们在大多数测试框架中都无法测试,我将文件路径作为类的构造函数中的依赖项传递。

所以现在你只需要选择一个依赖注入容器,你可以找到几个项目来查看roy osherov´s blog并选择你的结论。

我个人喜欢结构图和简单注入你的实现就像这样简单(this benchmark

var container = new Container();
Configure the container (register)
container.Register<IStudentService, FileStudentService>();

然后你可以使用构造函数注入你的程序注入你的服务,这应该做的诀窍

我知道这不是一个完整的工作代码,但至少我只是想让你了解如何开始!

喝彩!