Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
PyCon Russia 2018 — Unit Testing
Search
Vadim Pushtaev
July 23, 2018
Programming
430
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
PyCon Russia 2018 — Unit Testing
Vadim Pushtaev
July 23, 2018
More Decks by Vadim Pushtaev
See All by Vadim Pushtaev
Perl course (5), testing
vadimpushtaev
0
120
MR::Go::Admin::Test
vadimpushtaev
0
97
Perl course (4), testing
vadimpushtaev
0
130
Perl course (4), db
vadimpushtaev
0
240
Perl course (4), oop
vadimpushtaev
1
200
Perl course (4), mod
vadimpushtaev
0
200
Perl course (3), testing
vadimpushtaev
0
110
Perl course (3), db
vadimpushtaev
0
96
Perl course (3), oop
vadimpushtaev
0
120
Other Decks in Programming
See All in Programming
AIとASP.NET Coreで雑Webアプリを作った話
mayuki
0
500
例外の正しい扱い方 そのエラー try-catchして大丈夫?
jinwatanabe
0
210
セキュリティの専門家じゃなくてもできる。「セキュリティ意識」をアップデートして サプライチェーン攻撃への耐性を高めよう。
tk3fftk
5
710
Modding RubyKaigi for Myself
yui_knk
0
920
Dataformのリポジトリを立ち上げるときにまずやること / dataform-day0-2026
snhryt
0
150
AutonomyとControlのあいだ:Graflowで記述するAIエージェント協調
myui
0
120
The Arts and Crafts of Work in the AI Era — Toward Mastery in Software Development
kuranuki
1
750
ローカルLLMを使ってB2Bサービスを作っていての学び
yaotti
0
160
TSKaigi Night Talks 2026_TypeScriptでサプライチェーンの整合性を型に閉じ込める
geekplus_tech
0
330
Technical Debt: Understanding it Rightly, Engaging it Rightly #LaravelLiveJP
shogogg
0
220
不変条件と整合性境界—ビジネスが決める設計判断と実現パターン / Invariants and Consistency Boundaries
nrslib
13
3.6k
A2UI という光を覗いてみる
satohjohn
1
130
Featured
See All Featured
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
3
150
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
28
3.5k
The SEO Collaboration Effect
kristinabergwall1
1
480
How to Grow Your eCommerce with AI & Automation
katarinadahlin
PRO
1
200
HTML-Aware ERB: The Path to Reactive Rendering @ RubyCon 2026, Rimini, Italy
marcoroth
1
180
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
55
3.4k
Avoiding the “Bad Training, Faster” Trap in the Age of AI
tmiket
0
170
The B2B funnel & how to create a winning content strategy
katarinadahlin
PRO
1
380
The Illustrated Children's Guide to Kubernetes
chrisshort
51
52k
Learning to Love Humans: Emotional Interface Design
aarron
275
41k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
55k
Taking LLMs out of the black box: A practical guide to human-in-the-loop distillation
inesmontani
PRO
3
2.3k
Transcript
UNIT TESTING Вадим Пуштаев
Принципы Реализация 02/34 Что мы хотим? План доклада
03/34 Что мы хотим?
Регрессия 04/34
Влияние на архитектуру 05/34
Понимание 06/34
Отладка 07/34
Комфорт 08/34
Принципы
f: X Y Test the interface, not the implemen- tation?
X Y 10/34
Test the interface, not the implemen- tation? Y f: X
Y X 11/34
Test first 12/34
Unit testing ≠ testing 13/34
14/34 unittest xUnit – SUnit – JUnit – RUnit →
RSpec – ...
unittest Meszaros, Gerard (2007) xUnit Test Patterns 15/34
Этапы теста Arrange Act Assert Setup Exercise Verify Teardown 16/34
Setup Память Файловая система База данных … 17/34
Гибкие параметры def create(dt=None): if dt is None: dt =
datetime.now() def download(requests_lib=None): if requests_lib is None: requests_lib = requests class Downloader: def __init__(self, config, logger): self._config = config self._logger = logger 18/34
19/34 mock from unittest import mock requests_lib = mock.MagicMock() requests_lib.get.return_value.status_code
= 404 @mock.patch('that.module.requests') def test_download(self, requests_lib): requests_lib.get.return_value.status_code = 404
20/34 Файловая система import tempfile� with tempfile.TemporaryFile() as f: f.write(b'Test
data\n') output = io.StringIO() output.write('Test data\n')
База данных Поддельная база 21/34
База данных Поддельная база SQLite 22/34
База данных Поддельная база SQLite Настоящая база 23/34
Данные в базе Копия реальной базы 24/34
Данные в базе Копия реальной базы Слепок реальной базы 25/34
Данные в базе Копия реальной базы Слепок реальной базы Вручную
подготовленные данные 26/34
Данные в базе Копия реальной базы Слепок реальной базы Вручную
подготовленные данные Пустая база 27/34
Данные в базе Копия реальной базы Слепок реальной базы Вручную
подготовленные данные Пустая база Фабрики 28/34
factory_boy import factory from . import models class UserFactory(factory.django.DjangoModelFactory): class
Meta: model = models.User first_name = factory.Sequence( lambda n: 'User #{}'.format(n) ) group = factory.SubFactory(GroupFactory) 29/34 user = UserFactory()
Транзакции setUp = BEGIN tearDown = ROLLBACK self.break_db() 30/34
def setUp(self): super(BaseTestCase, self).setUp() self._patchers = { 'etcd': patch('common.utils.etcd.Etcd.write'), 'celery':
patch('celery.current_app.send_task'), } self._patchers['etcd'].return_value = None self._patchers['celery'].return_value = True for patcher in self._patchers.values(): patcher.start() � Patchers 31/34
def assertDirExists(self, dir_path): self.assertTrue(os.path.isdir(dir_path)) def assertNotFileExists(self, file_path): self.assertFalse(os.path.exists(file_path)) def assertFileContent(self,
content, path): with open(path, 'rb') as fh: self.assertEqual(content, fh.read()) Custom asserts 32/34
@BaseTestCase.cases( ( 'dst', pytz.timezone('Europe/Moscow'), DT.utc(2011, 3, 27, 6, 12, 23),
# 10:12:23 (MSD) datetime.date(2011, 3, 27), ), ( 'no_dst', pytz.timezone('Europe/Moscow'), DT.utc(2016, 2, 7, 23, 43, 12), # 02:43:12 (MSK) datetime.date(2016, 2, 8), ), ) def test_date_of_time(self, timezone, dt, date): self.assertEqual(DT.date_of_time(dt, timezone), date) 33/34 Таблицы результатов https://bit.ly/2NvZdUT
Итого
Спасибо! @pushtaev @pythonetc Пуштаев Вадим
Тестирование приватного метода?
def count_german_letters(self): return len([ x for x in self._string if
self._is_german_letter(x) ]) def delete_german_letters(self): return ''.join( x for x in self._string if not self._is_german_letter(x) ) def _is_german_letter(self, c): return c in string.ascii_lowercase or c in 'ÄäÖöÜü ß'