0

I have a Mocking.sln which has two projects: Student (Class Library) and StudentStat (Console Application)

Student project has below details:

    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 project has below details:

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

This GetStudentData() method read details from DB and output details. Suppose this is my production code and I have no permission to change anything.

I have a overloaded version of GetStudentData() which takes filePath as a parameter and read the details from text file. Below is the method:

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;
    }

Now when I call StudentInfo.CalculateTotalMarks() in StudentStat.exe, I want this overloaded GetStudentData(string filepath) will be called instead of the other method (which reads data from DB), and shows me output.

I heard that this will be possible using NMock3. but I dont have any idea on that. Can you please share soem code samples..It will help me to learn NMock3 also. Any help is appreciated...

  • Sounds like what you're looking for is [Dependency Injection](http://stackoverflow.com/questions/130794/what-is-dependency-injection) – Dave Zych Aug 08 '13 at 00:41

1 Answers1

0

you can use a Test driven developement what you need to do is to refactor the code that you have there and implement the Interface segregation that is part of the SOLID Principle, I recommend you to read the roy osherov´s blog which is the father of the TDD, I learned TDD just by reading a book the art of unit testing (it could be old by now) but anyway in a nutshell what you need to do is to decouple you code and separate your implementations and just define a contract for it.

for example you can have this Interface which is going to define the methods of what you need to do.

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

and then you could have two different implementations

To keep it simple I'm just going copy and paste your SQL code but you must have in mind that the SQL commands need to be treated as dependencies in your TDD approach as well.

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;
        }
}

and then create a different implementation let´s say

   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;
        }

    }

just notice that your methods are not static anymore because they are not testable with most of the test framework out there and I pass the filepath as a dependency in the constructor of the class.

so now you just need to choose a Dependency Injection container there several projects that you can find take a look to this benchmark and choose your conclusions.

personally I like structuremap and simple Injector registering your implementation is much as simple like this (using SI)

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

and then you can inject your service using a constructor injection into your program and that should do the trick

I know that this is not a full working code but at least I just want to give you the idea of how you can start!

cheers!

pedrommuller
  • 14,865
  • 9
  • 65
  • 115