home-assistant.github.io/developers/development_testing/index.html
2018-03-03 16:19:35 +00:00

318 lines
19 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!--> <html> <!--<![endif]-->
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Testing your code - Home Assistant</title>
<meta name="author" content="Home Assistant">
<meta name="description" content="Make sure that your code passes the checks">
<meta name="viewport" content="width=device-width">
<link rel="canonical" href="https://home-assistant.io/developers/development_testing/">
<meta property="fb:app_id" content="338291289691179">
<meta property="og:title" content="Testing your code">
<meta property="og:site_name" content="Home Assistant">
<meta property="og:url" content="https://home-assistant.io/developers/development_testing/">
<meta property="og:type" content="website">
<meta property="og:description" content="Make sure that your code passes the checks">
<meta property="og:image" content="https://home-assistant.io/images/default-social.png">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@home_assistant">
<meta name="twitter:title" content="Testing your code">
<meta name="twitter:description" content="Make sure that your code passes the checks">
<meta name="twitter:image" content="https://home-assistant.io/images/default-social.png">
<link href="/stylesheets/screen.css" media="screen, projection, print" rel="stylesheet">
<link href="/atom.xml" rel="alternate" title="Home Assistant" type="application/atom+xml">
<link rel='shortcut icon' href='/images/favicon.ico' />
<link rel='icon' type='image/png' href='/images/favicon-192x192.png' sizes='192x192' />
</head>
<body >
<header class='site-header'>
<div class="grid-wrapper">
<div class="grid">
<div class="grid__item three-tenths lap-two-sixths palm-one-whole ha-title">
<a href="/" class="site-title">
<img width='40' src='/demo/favicon-192x192.png'>
<span>Home Assistant</span>
</a>
</div>
<div class="grid__item seven-tenths lap-four-sixths palm-one-whole">
<nav>
<input type="checkbox" id="toggle">
<label for="toggle" class="toggle" data-open="Main Menu" data-close="Close Menu"></label>
<ul class="menu pull-right">
<li><a href="/getting-started/">Getting started</a></li>
<li><a href="/components/">Components</a></li>
<li><a href="/docs/">Docs</a></li>
<li><a href="/cookbook/">Examples</a></li>
<li><a href="/developers/">Developers</a></li>
<li><a href="/blog/">Blog</a></li>
<li><a href="/help/">Need help?</a></li>
<li><a href='#' class='show-search'><i class="icon-search"></i></a></li>
</ul>
</nav>
<div class='search-container' style='display: none'>
<div class='search'>
<i class="icon-search"></i>
<input id='search' placeholder='Search the docs…'>
<a href='#' class='close'><i class="icon-remove-sign"></i></a>
</div>
</div>
</div>
</div>
</div>
</header>
<div class="grid-wrapper">
<div class="grid grid-center">
<div class="grid__item two-thirds lap-one-whole palm-one-whole">
<article class="page">
<header>
<h1 class="title indent">
Testing your code
</h1>
</header>
<hr class="divider">
<p>As states in the <a href="/developers/development_guidelines/">Style guidelines section</a> all code is checked to verify all unit tests pass and that the code passes the linting tools. Local testing is done using Tox, which has been installed as part of running <code class="highlighter-rouge">script/setup</code>. To start the tests, simply run it:</p>
<div class="language-bash highlighter-rouge"><pre class="highlight"><code><span class="gp">$ </span>tox
</code></pre>
</div>
<p><strong>Important:</strong> Run <code class="highlighter-rouge">tox</code> before you create your pull request to avoid annoying fixes.</p>
<p>Running Tox will run unit tests against the locally available Pythons, as well as validate the code and document style using <code class="highlighter-rouge">pycodestyle</code>, <code class="highlighter-rouge">pydocstyle</code> and <code class="highlighter-rouge">pylint</code>. You can run tests on only one tox target just use <code class="highlighter-rouge">-e</code> to select an environment. For example, <code class="highlighter-rouge">tox -e lint</code> runs the linters only, and <code class="highlighter-rouge">tox -e py34</code> runs unit tests only on Python 3.4.</p>
<p>Tox uses virtual environments under the hood to create isolated testing environments. The tox virtual environments will get out-of-date when requirements change, causing test errors. Run <code class="highlighter-rouge">tox -r</code> to tell Tox to recreate the virtual environments.</p>
<p>If you are working on tests for a component or platform and you need the dependencies available inside the Tox environment, update the list inside <code class="highlighter-rouge">script/gen_requirements_all.py</code>. Then run the script and then run <code class="highlighter-rouge">tox -r</code> to recreate the virtual environments.</p>
<h3><a class="title-link" name="running-single-tests-using-tox" href="#running-single-tests-using-tox"></a> Running single tests using Tox</h3>
<p>You can pass arguments via Tox to py.test to be able to run single test suites or test files. Replace <code class="highlighter-rouge">py36</code> with the Python version that you use.</p>
<div class="language-bash highlighter-rouge"><pre class="highlight"><code><span class="c"># Stop after the first test fails</span>
<span class="gp">$ </span>tox -e py36 -- tests/test_core.py -x
<span class="c"># Run test with specified name</span>
<span class="gp">$ </span>tox -e py36 -- tests/test_core.py -k test_split_entity_id
<span class="c"># Fail a test after it runs for 2 seconds</span>
<span class="gp">$ </span>tox -e py36 -- tests/test_core.py --timeout 2
<span class="c"># Show the 10 slowest tests</span>
<span class="gp">$ </span>tox -e py36 -- tests/test_core.py --duration<span class="o">=</span>10
</code></pre>
</div>
<h3><a class="title-link" name="testing-outside-of-tox" href="#testing-outside-of-tox"></a> Testing outside of Tox</h3>
<p>Running tox will invoke the full test suite. Even if you specify which tox target to run, you still run all tests inside that target. Thats not very convenient to quickly iterate on your code! To be able to run the specific test suites without Tox, youll need to install the test dependencies into your Python environment:</p>
<div class="language-bash highlighter-rouge"><pre class="highlight"><code><span class="gp">$ </span>pip3 install -r requirements_test_all.txt
</code></pre>
</div>
<p>Now that you have all test dependencies installed, you can run tests on individual files:</p>
<div class="language-bash highlighter-rouge"><pre class="highlight"><code><span class="gp">$ </span>flake8 homeassistant/core.py
<span class="gp">$ </span>pylint homeassistant/core.py
<span class="gp">$ </span>pydocstyle homeassistant/core.py
<span class="gp">$ </span>py.test tests/test_core.py
</code></pre>
</div>
<p>You can also run linting tests against all changed files, as reported by <code class="highlighter-rouge">git diff upstream/dev... --name-only</code>, using the <code class="highlighter-rouge">lint</code> script:</p>
<div class="language-bash highlighter-rouge"><pre class="highlight"><code><span class="gp">$ </span>script/lint
</code></pre>
</div>
<h3><a class="title-link" name="preventing-linter-errors" href="#preventing-linter-errors"></a> Preventing Linter Errors</h3>
<p>Save yourself the hassle of extra commits just to fix style errors by enabling the Flake8 git commit hook. Flake8 will check your code when you try to commit to the repository and block the commit if there are any style errors, which gives you a chance to fix them!</p>
<div class="language-bash highlighter-rouge"><pre class="highlight"><code><span class="gp">$ </span>pip3 install flake8 flake8-docstrings
<span class="gp">$ </span>flake8 --install-hook<span class="o">=</span>git
</code></pre>
</div>
<p>The <code class="highlighter-rouge">flake8-docstrings</code> extension will check docstrings according to <a href="https://www.python.org/dev/peps/pep-0257/">PEP257</a> when running Flake8.</p>
<h3><a class="title-link" name="notes-on-pylint-and-pep8-validation" href="#notes-on-pylint-and-pep8-validation"></a> Notes on PyLint and PEP8 validation</h3>
<p>If you cant avoid a PyLint warning, add a comment to disable the PyLint check for that line with <code class="highlighter-rouge"># pylint: disable=YOUR-ERROR-NAME</code>. Example of an unavoidable one is if PyLint incorrectly reports that a certain object doesnt have a certain member.</p>
</article>
</div>
<aside id="sidebar" class="grid__item one-third lap-one-whole palm-one-whole">
<div class="grid">
<section class="aside-module grid__item one-whole lap-one-half">
<div class='edit-github'><a href='https://github.com/home-assistant/home-assistant.github.io/tree/current/source/developers/development_testing.markdown'>Edit this page on GitHub</a></div>
<div class='section'>
<h1 class="title delta">Development Guide</h1>
<ul class='divided sidebar-menu'>
<li>
<a href='/developers/'>Introduction </a>
<ul>
<li><a href='/developers/architecture/'>Architecture </a></li>
<li><a href='/developers/architecture_components/'>Components </a></li>
</ul>
</li>
<li>
<a href='/developers/development/'>Starting with Development </a>
<ul>
<li><a href='/developers/development_environment/'>Setting up Environment </a></li>
<li><a href='/developers/development_submitting/'>Submit your Work </a></li>
<li><a href='/developers/development_checklist/'>Checklist </a></li>
<li><a href='/developers/development_guidelines/'>Style guidelines </a></li>
<li><a class='active' href='/developers/development_testing/'>Testing </a></li>
<li><a href='/developers/development_catching_up/'>Catching up with Reality </a></li>
<li><a href='/developers/development_validation/'>Validation </a></li>
</ul>
</li>
<li>
<a href='/developers/development_101/'>Development 101 </a>
<ul>
<li><a href='/developers/development_hass_object/'>Hass object </a></li>
<li><a href='/developers/development_events/'>Events </a></li>
<li><a href='/developers/development_states/'>States </a></li>
<li><a href='/developers/development_services/'>Services </a></li>
<li><a href='/developers/development_config/'>Config </a></li>
</ul>
</li>
<li>
<a href='/developers/add_new_platform/'>Creating a new platform (to support a new device) </a>
<ul>
<li><a href='/developers/code_review_platform/'>Checklist creating a platform </a></li>
<li><a href='/developers/platform_example_sensor/'>Example sensor platform </a></li>
<li><a href='/developers/platform_example_light/'>Example light platform </a></li>
</ul>
</li>
<li>
<a href='/developers/creating_components/'>Adding a new component </a>
<ul>
<li><a href='/developers/code_review_component/'>Checklist creating a component </a></li>
<li><a href='/developers/component_loading/'>Loading components </a></li>
<li><a href='/developers/component_deps_and_reqs/'>Requirements & Dependencies </a></li>
<li><a href='/developers/component_events/'>Handling events </a></li>
<li><a href='/developers/component_states/'>States </a></li>
<li><a href='/developers/component_visibility/'>Visibility </a></li>
<li><a href='/developers/component_generic_discovery/'>Loading Platforms </a></li>
<li><a href='/developers/component_discovery/'>Component Discovery </a></li>
</ul>
</li>
<li>
<a href='/developers/intent/'>Intents (handling voice responses) </a>
<ul>
<li><a href='/developers/intent/firing/'>Firing intents </a></li>
<li><a href='/developers/intent/handling/'>Handling intents </a></li>
<li><a href='/developers/intent/conversation/'>Registering sentences </a></li>
</ul>
</li>
<li>
<a href='/developers/asyncio/'>Asynchronous Programming </a>
<ul>
<li><a href='/developers/asyncio_101/'>Introduction to asyncio </a></li>
<li><a href='/developers/asyncio_categorizing_functions/'>Categorizing Functions </a></li>
<li><a href='/developers/asyncio_working_with_async/'>Working with Async </a></li>
<li><a href='/developers/asyncio_misc/'>Miscellaneous </a></li>
</ul>
</li>
<li>
<a href='/developers/frontend/'>Frontend Development </a>
<ul>
<li><a href='/developers/frontend_add_card/'>Add State Card </a></li>
<li><a href='/developers/frontend_add_more_info/'>Add More Info Dialog </a></li>
<li><a href='/developers/frontend_creating_custom_panels/'>Add Custom Panels </a></li>
<li><a href='/developers/frontend_creating_custom_ui/'>Add Custom UI </a></li>
</ul>
</li>
<li>
<a href='/developers/internationalization/'>Internationalization </a>
<ul>
<li><a href='/developers/internationalization/backend_localization/'>Backend Localization </a></li>
<li><a href='/developers/internationalization/custom_component_localization/'>Custom Component Localization </a></li>
<li><a href='/developers/internationalization/translation/'>Translation </a></li>
</ul>
</li>
<li>
<a href='/developers/hassio/architecture/'>Hass.io architecture </a>
<ul>
<li><a href='/developers/hassio/debugging/'>Debugging Hass.io </a></li>
</ul>
</li>
<li>
<a href='/developers/hassio/addon_development/'>Hass.io Add-on Development </a>
<ul>
<li><a href='/developers/hassio/addon_tutorial/'>Tutorial: Making your first add-on </a></li>
<li><a href='/developers/hassio/addon_config/'>Configuration </a></li>
<li><a href='/developers/hassio/addon_communication/'>Communication </a></li>
<li><a href='/developers/hassio/addon_testing/'>Local Testing </a></li>
<li><a href='/developers/hassio/addon_publishing/'>Publishing </a></li>
<li><a href='/developers/hassio/addon_presentation/'>Presentation </a></li>
<li><a href='/developers/hassio/addon_repository/'>Repositories </a></li>
</ul>
</li>
<li>
<a href='/developers/api/'>API </a>
<ul>
<li><a href='https://dev-docs.home-assistant.io/en/dev/'>Python API </a></li>
<li><a href='/developers/websocket_api/'>Websocket API </a></li>
<li><a href='/developers/rest_api/'>REST API </a></li>
<li><a href='/developers/python_api/'>Python REST API </a></li>
<li><a href='/developers/server_sent_events/'>Server-sent events </a></li>
</ul>
</li>
<li>
<a href='/developers/documentation/'>Website/Documentation </a>
<ul>
<li><a href='/developers/documentation/standards/'>Standards </a></li>
<li><a href='/developers/documentation/create_page/'>Create a new page </a></li>
</ul>
</li>
<li><a href='/developers/helpers/'>Online helpers </a></li>
<li><a href='/developers/releasing/'>Releasing </a></li>
<li><a href='/developers/maintenance/'>Maintenance </a></li>
<li>
Governance
<ul>
<li><a href='/developers/cla/'>Contributor License Agreement </a></li>
<li><a href='/privacy/'>Privacy Policy </a></li>
<li><a href='/tos/'>Terms of Service </a></li>
<li><a href='/code_of_conduct/'>Code of Conduct </a></li>
<li><a href='/developers/credits/'>Credits </a></li>
<li><a href='/developers/license/'>License </a></li>
</ul>
</li>
</ul>
</div>
</section>
</div>
</aside>
</div>
</div>
<footer>
<div class="grid-wrapper">
<div class="grid">
<div class="grid__item">
<div class="copyright">
<a rel="me" href='https://twitter.com/home_assistant'><i class="icon-twitter"></i></a>
<a rel="me" href='https://facebook.com/homeassistantio'><i class="icon-facebook"></i></a>
<a rel="me" href='https://plus.google.com/110560654828510104551'><i class="icon-google-plus"></i></a>
<a rel="me" href='https://github.com/home-assistant/home-assistant'><i class="icon-github"></i></a>
<div class="credit">
Contact us at <a href='mailto:hello@home-assistant.io'>hello@home-assistant.io</a> (no support!).<br>
Website powered by <a href='http://jekyllrb.com/'>Jekyll</a> and the <a href='https://github.com/coogie/oscailte'>Oscalite theme</a>.<br />
Hosted by <a href='https://pages.github.com/'>GitHub</a> and served by <a href='https://cloudflare.com'>CloudFlare</a>.
</div>
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">home-assistant.io</span> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License</a>.
</div>
</div>
</div>
</div>
</footer>
<script>
var _gaq=[['_setAccount','UA-57927901-1'],['_trackPageview']];
(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];
g.src=('https:'==location.protocol?'//ssl':'//www')+'.google-analytics.com/ga.js';
s.parentNode.insertBefore(g,s)}(document,'script'));
</script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/docsearch.js/2/docsearch.min.css" />
<script type="text/javascript" src="https://cdn.jsdelivr.net/docsearch.js/2/docsearch.min.js"></script>
<script type="text/javascript">
docsearch({
apiKey: 'ae96d94b201c5444c8a443093edf3efb',
indexName: 'home-assistant',
inputSelector: '#search',
debug: false // Set debug to true if you want to inspect the dropdown
});
document.querySelector('.search .close').addEventListener('click', function(ev) {
ev.preventDefault();
document.querySelector('.search-container').style.display = 'none';
});
document.querySelector('.show-search').addEventListener('click', function(ev) {
ev.preventDefault();
document.querySelector('.search-container').style.display = 'block';
document.getElementById('toggle').checked = false;
document.querySelector('.search-container input').focus();
});
</script>
</body>
</html>