тыжПрограммист
329 / 143 / 44
Регистрация: 21.04.2014
Сообщений: 637
1
.NET 4.x

Тестирование программы для работы с базой данных

23.05.2016, 02:43. Показов 1649. Ответов 5
Метки нет (Все метки)

Никогда не занимался юнит тестированием программ. Обычно всегда спасали консоль да куча MessageBox.

Прочитав информацию об тестировании встроенными средствами Visual Studio C# возникло пару вопросов.

В интернетах в качестве примеров тестируют обычно простые методы вроде 2+2 и 2>0.

У меня программа работает с базой данных. Конкретно с mdb файлом. Структура программы по большей части набор событий да запросов к базе.

Вопрос 1. Как производить тестирование методов подобных этому. Да и вообще любых методов касательно баз данных
C#
1
2
3
4
5
        public void UpdatePredmeti(string value1, string value2, string id)
        {
            command = new OleDbCommand(string.Format("UPDATE Предметы SET Код_преподавателя = {0}, Название = '{1}' WHERE Код = {2};",value1,value2,id), connection);
            command.ExecuteNonQuery();
        }
И можно ли тестировать события (нажатие на кнопку и прочие). Например
C#
1
2
3
4
        private void справкаToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Help.ShowHelp(this, "help.chm");
        }
C#
1
2
3
4
5
        private void оПрограммеToolStripMenuItem_Click(object sender, EventArgs e)
        {
            About about = new About();
            about.ShowDialog();
        }
А то исходя из задания нужно произвести тестирование всех модулей..а по-моей логике кроме методов проверки строки на соответствие регулярным выражением и тестить больше нечего
C#
1
2
3
4
5
6
7
        public static bool Group(string value)
        {
            Regex regex = new Regex("^(\\d+(-\\d+)?)$");
            if (regex.IsMatch(value))
                return true;
            return false;
        }
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
23.05.2016, 02:43
Ответы с готовыми решениями:

Посоветуйте книгу для работы с базой данных
Читал книгу Visual C# 2008. Базовый курс (авторы Уотсон К., Нейгел К, Педерсен Я.Х., Рид Д.,...

Ошибка работы с базой. Установка программы
Добрый день! У меня вопрос. Есть приложение разработаное на языке C# в среде Microsoft Visual...

Где можно посмотреть примеры (исходники) работы с базой данных на C#
Где можно посмотреть примеры (исходники) работы с базой данных на C#, работа с XML,SQL. Просто не...

[NUnit 3] Как правильно проверить методы работы с базой данных?
Здравствуйте. Пишу приложение по работе с БД на базе MSSQL CE. Написал библиотеку по работе с БД....

5
Эксперт .NET
9798 / 7168 / 1141
Регистрация: 21.01.2016
Сообщений: 27,264
23.05.2016, 05:45 2
LonerZzz, модульное тестирование подразумевает, что твоя программа из этих самых модулей и состоит. Судя по примерам кода, что ты представил, твоя программа не модульная. Чтобы сделать твою программу тестопригодной тебе нужно будет разобраться в таких вещах как внедрение зависимостей, разделение обязанностей и прочем.

Почитать об этом ты можешь в таких хороших книгах:
* Марк Симан: Внедрение зависимостей в .NET
* Рой Ошероув: Искусство автономного тестирования с примерами на С#

Причём хочу заметить, что прочтение хотя бы первой книги обязательно для того, чтобы понять как делать тестопригодный код. Ну, или, ты можешь попросить кого-нибудь, чтобы за тебя всё сделали. Это всё потому, что такой вопрос не решается простым советом "сюда допиши это, туда добавь то и готово!". За пять минут не разберёшься.
1
тыжПрограммист
329 / 143 / 44
Регистрация: 21.04.2014
Сообщений: 637
23.05.2016, 19:33  [ТС] 3
Цитата Сообщение от Usaga Посмотреть сообщение
что твоя программа из этих самых модулей и состоит.
Роль модулей могут играть структуры данных, библиотеки функций, классы, сервисы и др. программные единицы, реализующие некоторую функциональность и предоставляющие интерфейс к ней.
Всё это у меня есть. Есть класс для работы непосредственно с базой. Есть класс для проверки вводимых значений. И так далее. Связи как я понимаю тоже будут. Ибо классы взаимосвязаны.

Пробежался по книге. Начитался по заглушки и прочие ништяки. Всё же вопрос остался.
Как правильно тестировать классы типа такого?
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
using System.Data;
using System.Data.OleDb;
using System.Windows.Forms;
 
namespace Kafedra
{
    public class DB
    {
        private OleDbConnection connection;     // Объект для установки подключения с файлом базы данных
        private OleDbDataAdapter dataAdapter;   // 
        private OleDbCommand command;           // 
        private DataTable dataTable;            // 
 
        public int OpenConnection()
        {
            try
            {
                connection = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=Kafedra.mdb;Persist Security Info=False;");
                connection.Open();
            } catch(OleDbException)
            {
                return -1;
            }
            return 1;
        }
 
        public void CloseConnection()
        {
            connection.Close();
        }
 
        public DataTable SelectKafedra()
        {
            dataAdapter = new OleDbDataAdapter("SELECT Кафедры.Код, Кафедры.Название FROM Кафедры WHERE Кафедры.Удалено = 0;", connection);
            dataTable = new DataTable();
            dataAdapter.Fill(dataTable);
 
            return dataTable;
        }
 
        public DataTable SelectPrepodavateli()
        {
            dataAdapter = new OleDbDataAdapter("SELECT Преподаватели.Код, Преподаватели.Код_кафедры, Преподаватели.ФИО, Кафедры.Название AS Кафедра, Преподаватели.Должность " +
                                               "FROM Кафедры INNER JOIN Преподаватели ON Кафедры.Код = Преподаватели.Код_кафедры WHERE Преподаватели.Удалено = 0;", connection);
            dataTable = new DataTable();
            dataAdapter.Fill(dataTable);
 
            return dataTable;
        }
 
        public DataTable SelectStydenti()
        {
            dataAdapter = new OleDbDataAdapter("SELECT Студенты.Код, Студенты.ФИО, Студенты.Группа FROM Студенты WHERE Студенты.Удалено = 0;", connection);
            dataTable = new DataTable();
            dataAdapter.Fill(dataTable);
 
            return dataTable;
        }
 
        public DataTable SelectPraktika()
        {
            dataAdapter = new OleDbDataAdapter("SELECT Практика.Код, Практика.Код_преподавателя, Практика.Код_студента, Преподаватели.ФИО AS Преподаватель, Студенты.ФИО AS Студент, Практика.Оценка " +
                                               "FROM Студенты INNER JOIN (Преподаватели INNER JOIN Практика ON Преподаватели.Код = Практика.Код_преподавателя) ON Студенты.Код = Практика.Код_студента WHERE Практика.Удалено = 0;", connection);
            dataTable = new DataTable();
            dataAdapter.Fill(dataTable);
 
            return dataTable;
        }
 
        public DataTable SelectRaspisanie()
        {
            dataAdapter = new OleDbDataAdapter("SELECT Расписание.Код, Расписание.Код_преподавателя, Преподаватели.ФИО, Расписание.Время " +
                                               "FROM Преподаватели INNER JOIN Расписание ON Преподаватели.Код = Расписание.Код_преподавателя WHERE Расписание.Удалено = 0;", connection);
            dataTable = new DataTable();
            dataAdapter.Fill(dataTable);
 
            return dataTable;
        }
 
        public DataTable SelectPredmeti()
        {
            dataAdapter = new OleDbDataAdapter("SELECT Предметы.Код, Предметы.Код_преподавателя, Преподаватели.ФИО, Предметы.Название " +
                                               "FROM Преподаватели INNER JOIN Предметы ON Преподаватели.Код = Предметы.Код_преподавателя WHERE Предметы.Удалено = 0;", connection);
            dataTable = new DataTable();
            dataAdapter.Fill(dataTable);
 
            return dataTable;
        }
 
        public void InsertKafedra(string value)
        {
            command = new OleDbCommand(string.Format("INSERT INTO Кафедры (Название) VALUES ('{0}');", value), connection);
            command.ExecuteNonQuery();
        }
 
        public void InsertPrepodavaeli(string value1, string value2, string value3)
        {
            command = new OleDbCommand(string.Format("INSERT INTO Преподаватели (Код_кафедры, ФИО, Должность) VALUES ({0}, '{1}', '{2}');",value1,value2,value3), connection);
            command.ExecuteNonQuery();
        }
 
        public void InsertStydenti(string value1, string value2)
        {
            command = new OleDbCommand(string.Format("INSERT INTO Студенты (ФИО,Группа) VALUES ('{0}', '{1}');", value1, value2), connection);
            command.ExecuteNonQuery();
        }
 
        public void InsertPraktika(string value1, string value2, string value3)
        {
            command = new OleDbCommand(string.Format("INSERT INTO Практика (Код_преподавателя, Код_студента, Оценка) VALUES ({0}, {1}, {2});", value1, value2, value3), connection);
            command.ExecuteNonQuery();
        }
 
        public void InsertRaspisanie(string value1, string value2)
        {
            command = new OleDbCommand(string.Format("INSERT INTO Расписание (Код_преподавателя, Время) VALUES ({0}, '{1}');", value1, value2), connection);
            command.ExecuteNonQuery();
        }
 
        public void InsertPredmeti(string value1, string value2)
        {
            command = new OleDbCommand(string.Format("INSERT INTO Предметы (Код_преподавателя, Название) VALUES ({0}, '{1}');", value1, value2), connection);
            command.ExecuteNonQuery();
        }
 
        public void UpdateKafedra(string value, string id)
        {
            command = new OleDbCommand(string.Format("UPDATE Кафедры SET Название = '{0}' WHERE Код = {1};", value, id), connection);
            command.ExecuteNonQuery();
        }
 
        public void UpdatePrepodavateli(string value1, string value2, string value3, string id)
        {
            command = new OleDbCommand(string.Format("UPDATE Преподаватели SET Код_кафедры = {0}, ФИО = '{1}', Должность = '{2}' WHERE Код = {3};", value1, value2, value3, id), connection);
            command.ExecuteNonQuery();
        }
 
        public void UpdateStydenti(string value1,string value2, string id)
        {
            command = new OleDbCommand(string.Format("UPDATE Студенты SET ФИО = '{0}', Группа = '{1}' WHERE Код = {2};", value1, value2, id), connection);
            command.ExecuteNonQuery();
        }
 
        public void UpdatePraktika(string value1, string value2, string value3, string id)
        {
            command = new OleDbCommand(string.Format("UPDATE Практика SET Код_преподавателя = {0}, Код_студента = {1}, Оценка = {2} WHERE Код = {3};", value1, value2, value3, id), connection);
            command.ExecuteNonQuery();
        }
 
        public void UpdateRaspisanie(string value1, string value2, string id)
        {
            command = new OleDbCommand(string.Format("UPDATE Расписание SET Код_преподавателя = {0}, Время = '{1}' WHERE Код = {2};", value1, value2, id), connection);
            command.ExecuteNonQuery();
        }
 
        public void UpdatePredmeti(string value1, string value2, string id)
        {
            command = new OleDbCommand(string.Format("UPDATE Предметы SET Код_преподавателя = {0}, Название = '{1}' WHERE Код = {2};",value1,value2,id), connection);
            command.ExecuteNonQuery();
        }
 
        public void Delete(string table, string id)
        {
            command = new OleDbCommand("UPDATE " + table + " SET Удалено = 1 WHERE Код = " + id + ";", connection);
            command.ExecuteNonQuery();
        }
        public DataTable getDataTable()
        {
            return dataTable;
        }
    }
}
0
Эксперт .NET
9798 / 7168 / 1141
Регистрация: 21.01.2016
Сообщений: 27,264
23.05.2016, 20:05 4
Цитата Сообщение от LonerZzz Посмотреть сообщение
реализующие некоторую функциональность и предоставляющие интерфейс к ней.
Вот самое главное. Все твои классы должны взаимодействовать друг с другом только через интерфейсы. И получать свои зависимости классы должны извне (например через конструктор) или от настраиваемой (для целей тестирования) специализированной службы (DI-контейнер, сервис-локатор).

Только тогда ты сможешь тестировать своих классы по одиночке, заменяя их зависимости заглушками и суррогатами имитирующими реальные рабочие условия.

Но при всём при этом у тебя в программе будут вещи тебе не подконтрольные, а именно - сторонние технологии (UI, работа с БД, COM, файловая система и т.д.). Их ты, естественно, протестировать не сможешь (да и не надо это). Выход тут простой - изолировать сторонние технологии в отдельные классы и заменять их суррогатами во время тестирования. Судя по приведённому тобой коду, с БД ты так и поступил. Осталось только выделить из класса DB интерфейс (скажем IDB) и заставить код, работающей с базой данных использовать интерфейс, а не сам класс DB.
1
тыжПрограммист
329 / 143 / 44
Регистрация: 21.04.2014
Сообщений: 637
23.05.2016, 21:19  [ТС] 5
Вроде как всё понял. Остался последний вопрос. По поводу заглушек. Например у меня есть метод
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
        private void DeleteItem(string value)
        {
            if (MessageBox.Show("Вы действительно хотите удалить указанную запись?", "Подтверждение удаления", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
 
                switch (value)
                {
                    case "Кафедры":
                        db.Delete("Кафедры", dataGridView1[0, dataGridView1.CurrentRow.Index].Value.ToString());
                        FillDataGridView("Кафедры");
                        break;
 
                    case "Преподаватели":
                        db.Delete("Преподаватели", dataGridView1[0, dataGridView1.CurrentRow.Index].Value.ToString());
                        FillDataGridView("Преподаватели");
                        break;
 
                    case "Студенты":
                        db.Delete("Студенты", dataGridView1[0, dataGridView1.CurrentRow.Index].Value.ToString());
                        FillDataGridView("Студенты");
                        break;
 
                    case "Практика":
                        db.Delete("Практика", dataGridView1[0, dataGridView1.CurrentRow.Index].Value.ToString());
                        FillDataGridView("Практика");
                        break;
 
                    case "Расписание":
                        db.Delete("Расписание", dataGridView1[0, dataGridView1.CurrentRow.Index].Value.ToString());
                        FillDataGridView("Расписание");
                        break;
 
                    case "Предметы":
                        db.Delete("Предметы", dataGridView1[0, dataGridView1.CurrentRow.Index].Value.ToString());
                        FillDataGridView("Предметы");
                        break;
 
                    default:
                        break;
                }
        }
Я написал интерфейс и всё прочее, что вы советовали. Исходя из кода..тут происходит работа с бд и интерфейсом
C#
1
2
                        db.Delete("Предметы", dataGridView1[0, dataGridView1.CurrentRow.Index].Value.ToString());
                        FillDataGridView("Предметы");
я хочу написать заглушку для данного метода. Для этого я создал новый класс унаследовал его от интерфейса. Создал такой же метод в данном классе.
Теперь нужно выпилить из кода работу с не тестируемыми штучками. Так как 2 указанных метода вышы ничего не возвращают после их выполнения я пришёл к тому что их удаление ни на что не повлияет(в рамках теста)
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
        private void DeleteItem(string value)
        {
                switch (value)
                {
                    case "Кафедры":
 
                        break;
 
                    case "Преподаватели":
 
                        break;
 
                    case "Студенты":
 
                        break;
 
                    case "Практика":
 
                        break;
 
                    case "Расписание":
 
                        break;
 
                    case "Предметы":
 
                        break;
 
                    default:
                        break;
                }
        }
Но теперь судя по коду и тестить нечего.
Можно конечно вместо void возвращать какое-либо значение после каждого case. Ну и в тест методе проверять на ожидаемый результат. Или же вообще не стоит тестировать данный метод? как лучше поступить?
0
Эксперт .NET
9798 / 7168 / 1141
Регистрация: 21.01.2016
Сообщений: 27,264
24.05.2016, 07:38 6
Лучший ответ Сообщение было отмечено LonerZzz как решение

Решение

Цитата Сообщение от LonerZzz Посмотреть сообщение
я хочу написать заглушку для данного метода. Для этого я создал новый класс унаследовал его от интерфейса. Создал такой же метод в данном классе.
Теперь нужно выпилить из кода работу с не тестируемыми штучками. Так как 2 указанных метода вышы ничего не возвращают после их выполнения я пришёл к тому что их удаление ни на что не повлияет(в рамках теста)


Всё не так! "Выпилить код с нетестируемыми штучками" - значит видоизменить метод таким образом, чтобы логика его работы не нарушалась. А ты же просто всё из метода повыкидывал. И новый класс создавать не нужно. Просто на существующем выполняешь команду "Refactor -> Extract Interface" и получаешь интерфейс твоего класса.

Настоятельно рекомендую почитать литературу, что я привёл выше. Если время у тебя ещё есть, конечно .
1
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
24.05.2016, 07:38
Помогаю со студенческими работами здесь

Класс для управления базой данных
Здравствуйте! Прошу помочь с проблемой. Столкнулся с ней когда стало нужно сделать абстрактный...

Класс для работы с базой данных
Подскажите, пожалуйста, гарантирует ли данный класс закрытие connection по завершению работы с ним...

Программа для работы с базой данных
Ya doljen v ocheni kratkii sroc zdelati v visual c++ programu dlea raboty sa bzami danih, no ya v...

Хостинг для работы с базой данных
Здравствуйте. Встала такая задача: необходимо создать небольшой сайт, на котором зарегистрированные...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
6
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2022, CyberForum.ru