Как вызвать перегруженный метод вместо реального метода
У меня есть 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(
) метод чтения деталей из БД и вывода деталей. Предположим, это мой рабочий код, и у меня нет разрешения что-либо менять.
У меня перегруженная версия 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)
будет вызван вместо другого метода (который читает данные из БД) и покажет мне вывод.
Я слышал, что это будет возможно с помощью NMock3
, но я понятия не имею об этом. Можете ли вы поделиться примерами кода соем.. Это поможет мне узнать NMock3
также. Любая помощь приветствуется...
1 ответ
Вы можете использовать тестовую разработку, что вам нужно сделать, это провести рефакторинг кода, который у вас есть, и реализовать сегрегацию интерфейса, которая является частью принципа SOLID, я рекомендую вам прочитать блог Роя Ошерова, который является отцом TDD, я выучил TDD, просто прочитав книгу об искусстве модульного тестирования (оно может быть уже устаревшим), но в любом случае, в двух словах, вам нужно разделить код, отделить реализации и просто определить для него контракт.,
например, у вас может быть этот интерфейс, который будет определять методы того, что вам нужно делать.
interface IStudentService{
Dictionary<int, int> GetStudentData()
}
и тогда вы могли бы иметь две разные реализации
Для простоты я просто собираюсь скопировать и вставить ваш код SQL, но вы должны иметь в виду, что команды SQL также должны рассматриваться как зависимости в вашем подходе TDD.
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;
}
}
просто заметьте, что ваши методы больше не являются статичными, потому что они не тестируемы с большинством тестовых сред, и я передаю путь к файлу как зависимость в конструкторе класса.
так что теперь вам просто нужно выбрать контейнер Dependency Injection, и вы можете найти несколько проектов, взглянуть на этот тест и сделать выводы.
лично мне нравится структура карты и простой Injector, регистрация вашей реализации очень проста ( с использованием SI)
var container = new Container();
Configure the container (register)
container.Register<IStudentService, FileStudentService>();
а затем вы можете внедрить свой сервис, используя конструктор инъекций в вашу программу, и это должно сделать свое дело
Я знаю, что это не полный рабочий код, но, по крайней мере, я просто хочу дать вам представление о том, как вы можете начать!
ура!