Тестирование, GUI и конкурентность¶
Краткий справочник по вопросам тестирования кода, оконных приложений и параллельных вычислений в Python и Go.
1. Тестирование: модульное, функциональное, приёмочное; пирамида тестов; pytest и testing¶
Модульное (unit) тестирование проверяет отдельную функцию или метод в изоляции, функциональное — поведение фичи целиком (часто через её внешний интерфейс), а приёмочное (acceptance) — соответствие системы требованиям заказчика, обычно с точки зрения пользователя. Пирамида тестов рекомендует держать много быстрых unit-тестов в основании, меньше интеграционных в середине и совсем немного медленных end-to-end сверху. В Python стандартом де-факто стал pytest (тесты — обычные функции test_* с assert), в Go тесты пишут через встроенный пакет testing (функции func TestXxx(t *testing.T)).
func TestAdd(t *testing.T) {
if got := Add(2, 3); got != 5 {
t.Errorf("Add(2,3) = %d; want 5", got)
}
}
2. Создание оконных приложений: GUI, Tkinter и PyQt, Fyne; цикл событий и виджеты¶
GUI (графический интерфейс) строится из виджетов — кнопок, полей ввода, меток — которые размещаются в окне и реагируют на действия пользователя. В основе любого GUI лежит цикл событий (event loop): программа ждёт события (клик, нажатие клавиши) и вызывает привязанный к нему обработчик (callback). В Python для этого используют Tkinter (входит в стандартную библиотеку, прост для старта) и PyQt (мощный, на базе Qt, со сложным API), в Go популярна кроссплатформенная библиотека Fyne.
import tkinter as tk
root = tk.Tk()
tk.Button(root, text="OK", command=lambda: print("click")).pack()
root.mainloop() # запуск цикла событий
3. Параллельные вычисления: конкурентность vs параллелизм; asyncio и потоки, горутины и каналы¶
Конкурентность — это способ структурировать программу так, чтобы несколько задач выполнялись с чередованием (даже на одном ядре), а параллелизм — их одновременное выполнение на нескольких ядрах. В Python конкурентность дают потоки (threading, но из-за GIL реального параллелизма CPU-нагрузки нет) и asyncio (кооперативная многозадачность через async/await и единый event loop), а для параллелизма по CPU берут процессы (multiprocessing). В Go конкурентность встроена в язык: лёгкие горутины (go f()) общаются через каналы (chan), реализуя принцип «не передавай память через коммуникацию — общайся, передавая данные».
ch := make(chan int)
go func() { ch <- 42 }() // горутина шлёт значение
fmt.Println(<-ch) // основной поток получает