Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
PyCon Russia 2018 — Unit Testing
Search
Vadim Pushtaev
July 23, 2018
Programming
440
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
130
MR::Go::Admin::Test
vadimpushtaev
0
98
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
210
Perl course (3), testing
vadimpushtaev
0
110
Perl course (3), db
vadimpushtaev
0
97
Perl course (3), oop
vadimpushtaev
0
120
Other Decks in Programming
See All in Programming
GKE アップグレード前に知っておきたい Blue/Green と PDB の関係
stkk
0
160
Claude Codeを組織的に動かして月400PRを実現した話
happy_ryo
0
270
Vibes Containers 〜AIで変わるコンテナ設計と運用〜
tkikuc
3
520
週末にAI-DLCを本気で回したら$1,600溶けた
hbashimizu
0
130
Building an Out-of-Order CPU
latte72
1
750
20260914 AIエージェント時代のPlatform Engineering LLM基盤とプロダクトの責務境界線
kanfab1
2
620
thread_parallel_with_free-threaded_Python_and_NumPy.pdf
riku_sakamoto
0
290
数年滞っていたダークモード対応をおよそ2週間で完了させる
chigichan24
0
700
Omarchy Tokyo やると聞いて UMPC 買ってセットアップしてきた
mtsmfm
0
130
What We Talk About When We Talk About XP
m_seki
2
490
DynamoDBの基礎を振り返りながらベクトル検索機能を理解する
musan
3
280
ALB ログから Trace を気合で繋げる技術
fohte
7
880
Featured
See All Featured
Paper Plane (Part 1)
katiecoart
PRO
1
11k
Google's AI Overviews - The New Search
badams
0
1.6k
YesSQL, Process and Tooling at Scale
rocio
174
15k
Data-driven link building: lessons from a $708K investment (BrightonSEO talk)
szymonslowik
1
1.3k
Exploring anti-patterns in Rails
aemeredith
3
500
What's in a price? How to price your products and services
michaelherold
247
13k
The Pragmatic Product Professional
lauravandoore
37
7.4k
A better future with KSS
kneath
240
18k
How to Talk to Developers About Accessibility
jct
2
540
DevOps and Value Stream Thinking: Enabling flow, efficiency and business value
helenjbeal
1
380
Marketing Yourself as an Engineer | Alaka | Gurzu
gurzu
0
300
Java REST API Framework Comparison - PWX 2021
mraible
34
9.7k
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 'ÄäÖöÜü ß'