forked from pyvec/naucse.python.cz
-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Deploying to gh-pages from @ f007fb2 🚀
- Loading branch information
1 parent
3ccbc1d
commit 7e29db5
Showing
11 changed files
with
1,781 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
294 changes: 294 additions & 0 deletions
294
2024/pyladies-en-vienna-2024-autumn/beginners-en/modules/index.html
Large diffs are not rendered by default.
Oops, something went wrong.
268 changes: 268 additions & 0 deletions
268
2024/pyladies-en-vienna-2024-autumn/beginners-en/testing-continued/index.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,268 @@ | ||
|
||
<!doctype html> | ||
<html lang="cs"> | ||
<head> | ||
<meta charset="utf-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> | ||
<title> | ||
|
||
Beginners course PyLadies Vienna: Testing Continued | ||
|
||
</title> | ||
|
||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N" crossorigin="anonymous"> | ||
|
||
|
||
<link rel="icon" type="image/x-icon" href= "/static/img/who_96px.png"> | ||
<link rel="stylesheet" href="/static/css/naucse.css"> | ||
<link rel="stylesheet" href="/static/css/body.css"> | ||
<link rel="stylesheet" href="/static/css/pygments-lovelace-style.css"> | ||
<link rel="stylesheet" href="/static/css/ipython.css"> | ||
|
||
|
||
<link rel="canonical" href="https://naucse.python.cz/lessons/beginners-en/testing-continued/" /> | ||
|
||
|
||
<style> | ||
|
||
|
||
|
||
</style> | ||
</head> | ||
|
||
<body> | ||
<nav class="header"> | ||
<ul class="container menu"> | ||
<li><a href="/" class="logo"><h1>PyLadies Vienna</h1></a></li> | ||
<li><a href="/sponsorship/" class="menu-link"><h2>Support Us</h2></a></li> | ||
<li><a href="/mentorship/" class="menu-link"><h2>Mentorship</h2></a></li> | ||
<li><a href="/runs/" class="menu-link"><h2>Courses</h2></a></li> | ||
</ul> | ||
</nav> | ||
|
||
|
||
|
||
<div class="page"> | ||
<div class="container"> | ||
|
||
|
||
|
||
|
||
|
||
<div class="lesson-content"> | ||
|
||
|
||
|
||
<h2>Negative tests</h2> | ||
<p>Tests that verify that a program works correctly | ||
under correct conditions are called <em>positive tests</em>. | ||
An exception raised during the positive testing lead to failure of the test.</p> | ||
<p>Tests which check behaviour for invalid inputs are called <em>negative tests</em>. | ||
The purpose of the negative testing is verification of the graceful handling | ||
of error states. Raising of an exception is often the expected behaviour | ||
of the tested code.</p> | ||
<p>For example, the <code>computer_move</code> function should raise an error | ||
(e.g., <code>ValueError</code>) when the board is full.</p> | ||
<div class="admonition note"><p>It is much better to raise an exception than doing nothing | ||
and silently letting the program get stuck elsewhere. | ||
You can use such function in a more complex program | ||
and be sure that it will raise an understandable error | ||
when it is called under bad conditions. | ||
The error helps you to fix the actual problem. The sooner you discover | ||
an error the easier is to fix it.</p> | ||
</div><p>Use the <code>with</code> statement and the <code>raises</code> function | ||
to test that your code raises the expected exception. | ||
The <code>raises</code> function is imported from the <code>pytest</code> module.</p> | ||
<div class="admonition note"><p>We have not talked about the <code>with</code> statement and context managers yet. | ||
But don't worry, you will learn about them later. Just check how it is used | ||
to test whether an exception is raised.</p> | ||
</div><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">pytest</span> | ||
|
||
<span class="kn">import</span> <span class="nn">tic_tac_toe</span> | ||
|
||
<span class="k">def</span> <span class="nf">test_move_failure</span><span class="p">():</span> | ||
<span class="k">with</span> <span class="n">pytest</span><span class="o">.</span><span class="n">raises</span><span class="p">(</span><span class="ne">ValueError</span><span class="p">):</span> | ||
<span class="n">tic_tac_toe</span><span class="o">.</span><span class="n">computer_move</span><span class="p">(</span><span class="s1">'oxoxoxoxoxoxoxoxoxox'</span><span class="p">)</span> | ||
</pre></div><p>Let's now try to edit the function for getting a perimeter of rectangle | ||
so that it raises a ValueError if any of the sides is smaller or equal to zero. | ||
Add a test for the new functionality.</p> | ||
<div class="solution" id="solution-0"> | ||
<h3>Solution</h3> | ||
<div class="solution-cover"> | ||
<a href="/2024/pyladies-en-vienna-2024-autumn/beginners-en/testing-continued/index/solutions/0/"><span class="link-text">Show solution</span></a> | ||
</div> | ||
<div class="solution-body" aria-hidden="true"> | ||
<div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">pytest</span> | ||
|
||
<span class="k">def</span> <span class="nf">find_rectangle_perimeter</span><span class="p">(</span><span class="n">width</span><span class="p">,</span> <span class="n">height</span><span class="p">):</span> | ||
<span class="w"> </span><span class="sd">""" Calculate perimeter of a rectangle from the given sides.</span> | ||
<span class="sd"> """</span> | ||
<span class="k">if</span> <span class="n">width</span> <span class="o"><</span> <span class="mi">0</span> <span class="ow">or</span> <span class="n">height</span> <span class="o"><</span> <span class="mi">0</span><span class="p">:</span> | ||
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">"Rectangle sides must be non-negative."</span><span class="p">)</span> | ||
<span class="k">return</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">(</span><span class="n">width</span> <span class="o">+</span> <span class="n">height</span><span class="p">)</span> | ||
|
||
<span class="k">def</span> <span class="nf">test_find_perimeter_exception_negative</span><span class="p">():</span> | ||
<span class="w"> </span><span class="sd">""" Tests of negative integer values as input</span> | ||
<span class="sd"> """</span> | ||
<span class="k">with</span> <span class="n">pytest</span><span class="o">.</span><span class="n">raises</span><span class="p">(</span><span class="ne">ValueError</span><span class="p">):</span> | ||
<span class="n">find_rectangle_perimeter</span><span class="p">(</span><span class="o">-</span><span class="mi">3</span><span class="p">,</span> <span class="mi">5</span><span class="p">)</span> | ||
</pre></div> | ||
</div> | ||
</div><h2>Pytest fixtures</h2> | ||
<p><code>Fixtures</code> in pytest are reusable components that set up specific states (e.g. database connections, test data).</p> | ||
<h3>Key Features</h3> | ||
<ul> | ||
<li>Reusability: Define a fixture once and use it across multiple test functions.</li> | ||
<li>Scoping: Fixtures can be scoped (available) at different levels like function, class, module, or session.</li> | ||
<li>Automatic Cleanup: Fixtures can be set up to automatically clean up resources after a test is done.</li> | ||
<li>Dependency Injection: Test functions can use fixtures by including them as arguments. (It is not possible to add "normal" arguments to test functions, only references to fixtures).</li> | ||
</ul> | ||
<p>You can easily create and use a <code>fixture in pytest</code> in a following way:</p> | ||
<div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">pytest</span> | ||
|
||
<span class="nd">@pytest</span><span class="o">.</span><span class="n">fixture</span> | ||
<span class="k">def</span> <span class="nf">sample_data</span><span class="p">():</span> | ||
<span class="k">return</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">]</span> | ||
<span class="k">def</span> <span class="nf">test_sum</span><span class="p">(</span><span class="n">sample_data</span><span class="p">):</span> | ||
<span class="k">assert</span> <span class="nb">sum</span><span class="p">(</span><span class="n">sample_data</span><span class="p">)</span> <span class="o">==</span> <span class="mi">10</span> | ||
</pre></div><p>By default <code>fixture</code> is called once per a test function - <code>scope=function</code> parameter of a fixture.</p> | ||
<p>For resource utilization purposes it could be useful to create a fixture only once per whole <code>module</code>:</p> | ||
<div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">pytest</span> | ||
<span class="c1"># A fixture to provide a configuration dictionary</span> | ||
<span class="nd">@pytest</span><span class="o">.</span><span class="n">fixture</span><span class="p">(</span><span class="n">scope</span><span class="o">=</span><span class="s2">"module"</span><span class="p">)</span> | ||
<span class="k">def</span> <span class="nf">config_data</span><span class="p">():</span> | ||
<span class="n">config</span> <span class="o">=</span> <span class="p">{</span> | ||
<span class="s2">"api_endpoint"</span><span class="p">:</span> <span class="s2">"http://api.example.com"</span><span class="p">,</span> | ||
<span class="s2">"retry_attempts"</span><span class="p">:</span> <span class="mi">5</span><span class="p">,</span> | ||
<span class="s2">"timeout"</span><span class="p">:</span> <span class="mi">10</span> | ||
<span class="p">}</span> | ||
<span class="k">return</span> <span class="n">config</span> | ||
<span class="c1"># Example test using the fixture</span> | ||
<span class="k">def</span> <span class="nf">test_api_endpoint</span><span class="p">(</span><span class="n">config_data</span><span class="p">):</span> | ||
<span class="k">assert</span> <span class="n">config_data</span><span class="p">[</span><span class="s2">"api_endpoint"</span><span class="p">]</span> <span class="o">==</span> <span class="s2">"http://api.example.com"</span> | ||
<span class="c1"># Another test using the same fixture</span> | ||
<span class="k">def</span> <span class="nf">test_retry_attempts</span><span class="p">(</span><span class="n">config_data</span><span class="p">):</span> | ||
<span class="k">assert</span> <span class="n">config_data</span><span class="p">[</span><span class="s2">"retry_attempts"</span><span class="p">]</span> <span class="o">==</span> <span class="mi">5</span> | ||
</pre></div><p>This approach is useful when the setup does not involve external resources that require explicit cleanup after the tests.</p> | ||
|
||
|
||
</div> | ||
|
||
|
||
|
||
|
||
|
||
<div class="row prev-next"> | ||
|
||
|
||
|
||
<div class="col text-left"> | ||
<a href="/2024/pyladies-en-vienna-2024-autumn/beginners-en/testing/">← <span class="d-none d-sm-inline">Testing</span></a> | ||
</div> | ||
|
||
|
||
|
||
|
||
<div class="col text-left"> | ||
<a href="/2024/pyladies-en-vienna-2024-autumn/sessions/testing/">↑ <span class="d-none d-sm-inline">Lesson: Modules, exceptions, testing</span></a> | ||
</div> | ||
|
||
|
||
|
||
|
||
<div class="col text-right"> | ||
<a href="/2024/pyladies-en-vienna-2024-autumn/sessions/testing/back/"><span class="d-none d-sm-inline">End of lesson</span> →</a> | ||
</div> | ||
|
||
|
||
|
||
</div> | ||
|
||
|
||
|
||
|
||
</div> | ||
</div> | ||
|
||
|
||
|
||
<script type="text/javascript" src="/static/js/solutions.js"></script> | ||
|
||
<div class="footer container"> | ||
<hr> | ||
<div class="lesson-attribution"> | ||
|
||
|
||
<p>Originally written by Lubomir Dolezal, 2023 for [PyLadies Vienna].</p> | ||
|
||
|
||
|
||
<p> | ||
Licence: | ||
<a href="https://creativecommons.org/licenses/by-sa/4.0/"> | ||
Creative Commons Attribution-ShareAlike 4.0 International | ||
</a> | ||
</p> | ||
|
||
|
||
|
||
</div> | ||
</div> | ||
<footer> | ||
<div class="container"> | ||
<div class="global-pyladies"> | ||
© 2024 PyLadies Vienna. All rights reserved. | ||
<br> | ||
<a href="/agb/">Impressum, AGB</a> | ||
<br> | ||
We are a part of <a href="https://pyladies.com">international PyLadies</a>. | ||
</div> | ||
<ul> | ||
<li> | ||
<a href="https://discord.gg/v2qdvbD2dn" target="_blank"> | ||
<img src="/static/img/discord-logo.png"> | ||
</a> | ||
</li> | ||
<li> | ||
<a href="mailto:[email protected]" > | ||
<img src="/static/img/mail-white.png"> | ||
</a> | ||
</li> | ||
<li> | ||
<a href="https://twitter.com/pyladies_vie" target="_blank"> | ||
<img src="/static/img/twitter-white.png"> | ||
</a> | ||
</li> | ||
<li> | ||
<a href="https://www.instagram.com/pyladies_vienna" target="_blank"> | ||
<img src="/static/img/instagram-logo.png"> | ||
</a> | ||
</li> | ||
<li> | ||
<a href="https://github.com/UndeadFairy/pyladies_vienna" target="_blank"> | ||
<img src="/static/img/github-white.png"> | ||
</a> | ||
</li> | ||
<li> | ||
<a href="https://www.meetup.com/PyLadies-Vienna/" target="_blank"> | ||
<img src="/static/img/meetup.png"> | ||
</a> | ||
</li> | ||
<li data-toggle="tooltip" title="Linkedin"> | ||
<a href="https://www.linkedin.com/company/pyladies-vienna" target="_blank"> | ||
<img src="/static/img/linkedin-logo.png"> | ||
</a> | ||
</li> | ||
</ul> | ||
</div> | ||
<div class="clear"></div> | ||
</footer> | ||
|
||
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script> | ||
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script> | ||
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-Fy6S3B9q64WdZWQUiU+q4/2Lc9npb8tCaSX9FK7E8HnRr0Jz8D6OP9dO5Vg3Q9ct" crossorigin="anonymous"></script> | ||
|
||
|
||
|
||
</body> | ||
</html> |
Oops, something went wrong.