Skip to content

Instantly share code, notes, and snippets.

@sirex
Last active May 4, 2016 20:14
Show Gist options
  • Save sirex/5f184fa6be4c82222c45c8d421770365 to your computer and use it in GitHub Desktop.
Save sirex/5f184fa6be4c82222c45c8d421770365 to your computer and use it in GitHub Desktop.
PyConLT 2016 slides
# http://editorconfig.org/
root = true
[*.{html,css}]
charset = utf-8
indent_style = space
end_of_line = lf
insert_final_newline = true
max_line_length = 120
indent_size = 2

How to set up:

mkvirtualenv -p /usr/bin/python3 slides
git clone --recursive [email protected]:sirex/rst2html5.git
pip install -e ./rst2html5
version = 3.3.0
reveal.js: reveal.js-$(version)
ln -s reveal.js-$(version) reveal.js
reveal.js-$(version): reveal.js-$(version).tar.gz
tar -xzf reveal.js-$(version).tar.gz
reveal.js-$(version).tar.gz:
wget https://github.com/hakimel/reveal.js/archive/$(version).tar.gz -O reveal.js-$(version).tar.gz
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="reveal.js/css/reveal.css">
<link rel="stylesheet" href="reveal.js/css/theme/black.css">
<link rel="stylesheet" href="reveal.js/lib/css/zenburn.css">
<style type="text/css">
.reveal table {
color: white;
}
.text-right {
text-align: right !important;
}
.reveal .slides ul {
display: block;
padding-left: 30px;
}
.reveal .slides ul li {
list-style: none;
font-size: 28px;
text-indent: -24px;
padding-top: 10px;
}
.reveal .slides ul li:before {
content: "·";
font-size: 80px;
vertical-align: middle;
line-height: 20px;
padding-right: 4px;
}
.smaller code {
font-size: 18px;
}
.reveal .mono {
font-family: monospace;
}
.reveal .code {
font-family: monospace;
background: #3f3f3f;
color: #dcdcdc;
padding: 2px 8px;
font-size: 24px;
}
.reveal pre.inline {
display: inline;
position: static;
padding: 26px 8px;
border: none;
box-shadow: none;
}
.reveal pre.inline code {
display: inline;
position: static;
font-size: 24px;
background: transparent;
line-height: 36px;
}
.reveal pre {
box-shadow: none;
}
</style>
</head>
<body>
<div class="reveal">
<div class="slides">
<section>
<pre><code class="python" style="text-align:center;font-size:42px;padding:42px;">import pytest</code></pre>
<p>Mantas Zimnickas</p>
<p>
<small>
<img src="pyconltlogo.png" style="border:none;vertical-align:middle;background:none;" alt="pyconlt logo">
PyConLT 2016
</small>
</p>
</section>
<section>
<h2>Demo</h2>
</section>
<section>
<h2>unittest</h2>
<pre><code class="python" data-trim data-noescape>
import unittest
class TestLen(unittest.TestCase):
def test_len(self):
self.assertEqual(len('foo'), 3)
</code></pre>
<ul>
<li>Sukurtas pagal <strong>Kent Beck</strong> <em>„Simple Smalltalk Testing: With Patterns“</em>
straipsnį.</li>
<li>Straipsnis parašytas 1989 metais (prieš 27 metus).</li>
<li>Pagal tą patį straipsnį sukurta nemažai <em>xUnit</em> stiliaus karkasų <em>SUnit</em>,
<em>JUnit</em>, <em>RUnit</em>, <em>xUnit.net</em>, ...).</li>
</ul>
</section>
<section>
<h2>doctest</h2>
<pre><code class="python" data-trim data-noescape>
>>> len('foo')
3
</code></pre>
<ul>
<li>Tinka paprastiems atvejams testuoti.</li>
<li>Nėra padoraus testų pradinės būsenos (<em>angl. fixtures</em>) valdymo.</li>
<li>Reikia atkartoti <em>Python REPL</em>, kas nėra labai patogu.</li>
</ul>
</section>
<section>
<h2>py.test</h2>
<pre><code class="python" data-trim data-noescape>
def test_len():
assert len('foo') == 3
</code></pre>
<ul>
<li>Geriausios dalys iš <em>unittest</em> ir <em>doctest</em> sudėtos į vieną.</li>
</ul>
</section>
<section>
<h2>Geriausias API, jokio API</h2>
<table>
<tbody class="mono">
<tr>
<td><pre class="inline"><code class="python" data-trim data-noescape>assertEqual(a, b)</code></pre></td>
<td><pre class="inline"><code class="python" data-trim data-noescape>assert a == b</code></pre></td>
</tr>
<tr>
<td><pre class="inline"><code class="python" data-trim data-noescape>assertNotEqual(a, b)</code></pre></td>
<td><pre class="inline"><code class="python" data-trim data-noescape>assert a != b</code></pre></td>
</tr>
<tr>
<td><pre class="inline"><code class="python" data-trim data-noescape>assertTrue(a)</code></pre></td>
<td><pre class="inline"><code class="python" data-trim data-noescape>assert a</code></pre></td>
</tr>
<tr>
<td><pre class="inline"><code class="python" data-trim data-noescape>assertFalse(a)</code></pre></td>
<td><pre class="inline"><code class="python" data-trim data-noescape>assert not a</code></pre></td>
</tr>
<tr>
<td><pre class="inline"><code class="python" data-trim data-noescape>assertIn(a, b)</code></pre></td>
<td><pre class="inline"><code class="python" data-trim data-noescape>assert a in b</code></pre></td>
</tr>
</tbody>
</table>
<ul>
<li>Python <em>unittest</em> modulis turi <strong>33</strong> <span class="code">assert*</span> metodus.</li>
</ul>
</section>
<section>
<h2>Pranešimai apie klaidas</h2>
<pre>$ nosetests test_pytest.py</pre>
<pre class="smaller"><code data-trim data-noescape>
Traceback (most recent call last):
File "lib/python3.4/site-packages/nose/case.py", line 198, in runTest
self.test(*self.arg)
File "test_pytest.py", line 9, in test_len
assert len('foo') == 2
AssertionError
</code></pre>
<pre>$ py.test --tb=native test_pytest.py</pre>
<pre class="smaller"><code data-trim data-noescape>
Traceback (most recent call last):
File "test_pytest.py", line 9, in test_len
assert len('foo') == 2
AssertionError: assert 3 == 2
+ where 3 = len('foo')
</code></pre>
</section>
<section>
<h2>Testų leidėjai</h2>
<table>
<thead>
<tr>
<th></th>
<th>Atsisiuntimų sk.</th>
<th>Atnaujinta</th>
</tr>
</thead>
<tbody>
<tr>
<td>py.test</td>
<td class="text-right">7,162,417</td>
<td class="text-right">2016-03-18</td>
</tr>
<tr>
<td>nose</td>
<td class="text-right">26,967,204</td>
<td class="text-right">2015-06-02</td>
</tr>
<tr>
<td>nose2</td>
<td class="text-right">268,291</td>
<td class="text-right">2016-03-15</td>
</tr>
<tr>
<td>zope.testrunner</td>
<td class="text-right">194,450</td>
<td class="text-right">2016-05-02</td>
</tr>
</tbody>
</table>
</section>
<section>
<h2>Testų leidimas</h2>
<pre>$ py.test</pre>
<pre>$ py.test tests</pre>
<pre>$ py.test tests/test_foobar.py</pre>
<pre>$ py.test tests/test_foobar.py::test_case</pre>
<pre>$ py.test tests/test_foobar.py::TestClass.test_method</pre>
</section>
<section data-transition="none">
<h2>Testų žymėjimas</h2>
<pre class="smaller"><code class="python" data-trim data-noescape>
@pytest.mark.slow
def test_len():
assert len('foo') == 3
</code></pre>
<pre>$ py.test -m slow</pre>
<pre>$ py.test -m 'not slow'</pre>
</section>
<section data-transition="none">
<h2>Pradinė būsena</h2>
<pre class="smaller"><code class="python" data-trim data-noescape>
@pytest.fixture
def browser():
return selenium.webdriver.Firefox()
def test_pytest(<mark>browser</mark>):
browser.get('http://pytest.org/')
assert 'pytest' in browser.title
def test_pycon(<mark>browser</mark>):
browser.get('http://pycon.lt/')
assert 'PyCon' in browser.title
</code></pre>
</section>
<section data-transition="none">
<h2>Pradinės būsenos apimtis</h2>
<pre class="smaller"><code class="python" data-trim data-noescape>
@pytest.fixture(<mark>scope='session'</mark>)
def browser():
return selenium.webdriver.Firefox()
def test_pytest(browser):
browser.get('http://pytest.org/')
assert 'pytest' in browser.title
def test_pycon(browser):
browser.get('http://pycon.lt/')
assert 'PyCon' in browser.title
</code></pre>
</section>
<section data-transition="none">
<h2>Pradinės būsenos atstatymas</h2>
<pre class="smaller"><code class="python" data-trim data-noescape>
@pytest.fixture(scope='session')
def browser(<mark>request</mark>):
driver = selenium.webdriver.Firefox()
<mark>request.addfinalizer(driver.quit)</mark>
return driver
def test_pytest(browser):
browser.get('http://pytest.org/')
assert 'pytest' in browser.title
def test_pycon(browser):
browser.get('http://pycon.lt/')
assert 'PyCon' in browser.title
</code></pre>
</section>
<section data-transition="none">
<h2>Parametrizuota pradinė būsena</h2>
<pre class="smaller"><code class="python" data-trim data-noescape>
@pytest.fixture(scope='session', <mark>params=(Firefox, Chrome)</mark>)
def browser(request):
driver = <mark>request.param()</mark>
request.addfinalizer(driver.quit)
return driver
def test_pytest(browser):
browser.get('http://pytest.org/')
assert 'pytest' in browser.title
def test_pycon(browser):
browser.get('http://pycon.lt/')
assert 'PyCon' in browser.title
</code></pre>
</section>
<section>
<h2>Perrašoma pradinė būsena</h2>
<pre class="smaller"><code class="python" data-trim data-noescape>
tests/
conftest.py # aprašytas app projekto lygyje
subfolder/
conftest.py # perrašytas app paketo lygyje
test_foo.py # perrašytas app modulio lygyje
def test_bar(app): # naudojamas app iš test_foo.py
pass
</code></pre>
<ul>
<li><span class="code">py.test --fixtures</span> išveda dokumentuotą pradinių būsenų sąrašą.</li>
</ul>
</section>
<section>
<h2>Kaip dėl mock dekoratorių?</h2>
<ul>
<li>Įprastinis <em>mock</em> naudojimas:</li>
</ul>
<pre class="smaller"><code class="python" data-trim data-noescape>
@mock.patch('os.chmod')
@mock.patch('os.remove')
@mock.patch('os.listdir')
def test_unix_fs(mocked_listdir, mocked_remove, mocked_chmod):
pass
</code></pre>
<ul>
<li><em>mocker</em> pradinės būsenos (<em>angl. fixture</em>) naudojimas:</li>
</ul>
<pre class="smaller"><code class="python" data-trim data-noescape>
def test_unix_fs(mocker):
mocker.patch('os.chmod')
mocker.patch('os.remove')
mocked_listdir = mocker.patch('os.listdir')
</code></pre>
<ul>
<li><span class="code">pip install pytest-mock</span> ir visą tai veiks.</li>
</ul>
</section>
<section>
<h2>Žurnalai ir išvestys</h2>
<ul>
<li><span class="code">pip install pytest-catchlog</span></li>
</ul>
<pre class="smaller"><code class="python" data-trim data-noescape>
def test_foo(caplog):
caplog.set_level(logging.ERROR, logger='my.logger')
assert caplog.text == 'foo bar'
</code></pre>
<pre class="smaller"><code class="txt" data-trim data-noescape>
----------------------- Captured stdlog call ----------------------
test_reporting.py 26 INFO text going to logger
----------------------- Captured stdout call ----------------------
text going to stdout
----------------------- Captured stderr call ----------------------
text going to stderr
==================== 2 failed in 0.02 seconds =====================
</code></pre>
<ul>
<li><span class="code">py.test -s</span> - neužlaikyti išvesties.</li>
</ul>
</section>
<section>
<h2>Įskiepiai</h2>
<pre class="smaller"><code class="python" data-trim data-noescape>
setup(
entry_points = {
'pytest11': ['name_of_plugin = myproject.pluginmodule']
},
)
</code></pre>
<pre class="smaller"><code class="python" data-trim data-noescape>
@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_call(item):
print('set up')
outcome = yield
print('tear down')
</code></pre>
</section>
</div>
</div>
<script src="reveal.js/lib/js/head.min.js"></script>
<script src="reveal.js/js/reveal.js"></script>
<script>
// Full list of configuration options available at:
// https://github.com/hakimel/reveal.js#configuration
Reveal.initialize({
controls: false,
progress: true,
history: true,
center: true,
transition: 'slide', // none/fade/slide/convex/concave/zoom
// Optional reveal.js plugins
dependencies: [
{ src: 'reveal.js/lib/js/classList.js', condition: function() { return !document.body.classList; } },
{ src: 'reveal.js/plugin/markdown/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: 'reveal.js/plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: 'reveal.js/plugin/highlight/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } },
{ src: 'reveal.js/plugin/zoom-js/zoom.js', async: true },
{ src: 'reveal.js/plugin/notes/notes.js', async: true }
]
});
</script>
</body>
</html>
def percent(part, whole):
return part / whole * 100
def test_pytest():
assert percent(2, 0) == 20
import unittest
def percent(part, whole):
return part / whole * 100
class TestUnitTest(unittest.TestCase):
def test_unittest(self):
self.assertEqual(percent(2, 0), 20)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment