diff --git a/docs/index.rst b/docs/index.rst
index 9ee19f8d..fb9d8aa7 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -77,6 +77,8 @@ the application structure. It is **easy to understand and change** it.
Explore the documentation to know more about the ``Dependency Injector``.
+.. _contents:
+
Contents
--------
diff --git a/docs/providers/index.rst b/docs/providers/index.rst
index 446f155c..901b6204 100644
--- a/docs/providers/index.rst
+++ b/docs/providers/index.rst
@@ -1,3 +1,5 @@
+.. _providers:
+
Providers
=========
diff --git a/docs/tutorials/aiohttp.rst b/docs/tutorials/aiohttp.rst
index 84f2d82e..2406c8b7 100644
--- a/docs/tutorials/aiohttp.rst
+++ b/docs/tutorials/aiohttp.rst
@@ -2,3 +2,5 @@ Aiohttp tutorial
================
Coming soon...
+
+.. disqus::
diff --git a/docs/tutorials/asyncio.rst b/docs/tutorials/asyncio.rst
index 406c3788..d32c8cd2 100644
--- a/docs/tutorials/asyncio.rst
+++ b/docs/tutorials/asyncio.rst
@@ -2,3 +2,5 @@ Asyncio tutorial
================
Coming soon...
+
+.. disqus::
diff --git a/docs/tutorials/flask.rst b/docs/tutorials/flask.rst
index de725e6c..e3db3b77 100644
--- a/docs/tutorials/flask.rst
+++ b/docs/tutorials/flask.rst
@@ -32,6 +32,8 @@ How does Github Navigator work?
- User can click on the repository, the repository owner or the last commit to open its web page
on the Github.
+.. image:: flask_images/screen_02.png
+
Prepare the environment
-----------------------
@@ -630,7 +632,6 @@ Create empty file ``services.py`` in the ``githubnavigator`` package:
├── config.yml
└── requirements.txt
-
and put next into it:
.. code-block:: python
@@ -903,5 +904,212 @@ The refactoring is done. We've made it cleaner.
Tests
-----
+It would be nice to add some tests. Let's do this.
+
+We will use `pytest `_ and
+`coverage `_.
+
+Edit ``requirements.txt``:
+
+.. code-block::
+ :emphasize-lines: 6-7
+
+ dependency-injector
+ flask
+ bootstrap-flask
+ pygithub
+ pyyaml
+ pytest-flask
+ pytest-cov
+
+And let's install it::
+
+ pip install -r requirements.txt
+
+
+Create empty file ``tests.py`` in the ``githubnavigator`` package:
+
+.. code-block::
+ :emphasize-lines: 10
+
+ ./
+ ├── githubnavigator/
+ │ ├── templates/
+ │ │ ├── base.html
+ │ │ └── index.html
+ │ ├── __init__.py
+ │ ├── application.py
+ │ ├── containers.py
+ │ ├── services.py
+ │ ├── tests.py
+ │ └── views.py
+ ├── venv/
+ ├── config.yml
+ └── requirements.txt
+
+and put next into it:
+
+.. code-block:: python
+ :emphasize-lines: 42,65
+
+ """Tests module."""
+
+ from unittest import mock
+
+ import pytest
+ from github import Github
+ from flask import url_for
+
+ from .application import create_app
+
+
+ @pytest.fixture
+ def app():
+ return create_app()
+
+
+ def test_index(client, app):
+ github_client_mock = mock.Mock(spec=Github)
+ github_client_mock.search_repositories.return_value = [
+ mock.Mock(
+ html_url='repo1-url',
+ name='repo1-name',
+ owner=mock.Mock(
+ login='owner1-login',
+ html_url='owner1-url',
+ avatar_url='owner1-avatar-url',
+ ),
+ get_commits=mock.Mock(return_value=[mock.Mock()]),
+ ),
+ mock.Mock(
+ html_url='repo2-url',
+ name='repo2-name',
+ owner=mock.Mock(
+ login='owner2-login',
+ html_url='owner2-url',
+ avatar_url='owner2-avatar-url',
+ ),
+ get_commits=mock.Mock(return_value=[mock.Mock()]),
+ ),
+ ]
+
+ with app.container.github_client.override(github_client_mock):
+ response = client.get(url_for('index'))
+
+ assert response.status_code == 200
+ assert b'Results found: 2' in response.data
+
+ assert b'repo1-url' in response.data
+ assert b'repo1-name' in response.data
+ assert b'owner1-login' in response.data
+ assert b'owner1-url' in response.data
+ assert b'owner1-avatar-url' in response.data
+
+ assert b'repo2-url' in response.data
+ assert b'repo2-name' in response.data
+ assert b'owner2-login' in response.data
+ assert b'owner2-url' in response.data
+ assert b'owner2-avatar-url' in response.data
+
+
+ def test_index_no_results(client, app):
+ github_client_mock = mock.Mock(spec=Github)
+ github_client_mock.search_repositories.return_value = []
+
+ with app.container.github_client.override(github_client_mock):
+ response = client.get(url_for('index'))
+
+ assert response.status_code == 200
+ assert b'Results found: 0' in response.data
+
+Now let's run it and check the coverage::
+
+ py.test githubnavigator/tests.py --cov=githubnavigator
+
+You should see:
+
+.. code-block::
+
+ platform darwin -- Python 3.8.3, pytest-5.4.3, py-1.9.0, pluggy-0.13.1
+ plugins: flask-1.0.0, cov-2.10.0
+ collected 2 items
+
+ githubnavigator/tests.py .. [100%]
+
+ ---------- coverage: platform darwin, python 3.8.3-final-0 -----------
+ Name Stmts Miss Cover
+ ----------------------------------------------------
+ githubnavigator/__init__.py 0 0 100%
+ githubnavigator/application.py 11 0 100%
+ githubnavigator/containers.py 13 0 100%
+ githubnavigator/services.py 14 0 100%
+ githubnavigator/tests.py 32 0 100%
+ githubnavigator/views.py 7 0 100%
+ ----------------------------------------------------
+ TOTAL 77 0 100%
+
+.. note::
+
+ Take a look on the highlights in the ``tests.py``.
+
+ It emphasizes the overriding of the ``Github`` API client.
+
Conclusion
----------
+
+We are done.
+
+It this tutorial we've build ``Flask`` application following dependency injection principle.
+We've used ``Dependency Injector`` as a dependency injection framework.
+
+The heart of this application is the container. It keeps all the application components and their
+dependencies in one place:
+
+.. code-block:: python
+
+ """Application containers module."""
+
+ from dependency_injector import containers, providers
+ from dependency_injector.ext import flask
+ from flask import Flask
+ from flask_bootstrap import Bootstrap
+ from github import Github
+
+ from . import services, views
+
+
+ class ApplicationContainer(containers.DeclarativeContainer):
+ """Application container."""
+
+ app = flask.Application(Flask, __name__)
+
+ bootstrap = flask.Extension(Bootstrap)
+
+ config = providers.Configuration()
+
+ github_client = providers.Factory(
+ Github,
+ login_or_token=config.github.auth_token,
+ timeout=config.github.request_timeout,
+ )
+
+ search_service = providers.Factory(
+ services.SearchService,
+ github_client=github_client,
+ )
+
+ index_view = flask.View(
+ views.index,
+ search_service=search_service,
+ default_query=config.search.default_query,
+ default_limit=config.search.default_limit,
+ )
+
+What's next?
+
+- Look at the other tutorials :ref:`tutorials`.
+- Know more about the :ref:`providers`.
+- Go to the :ref:`contents`.
+
+
+.. disqus::
diff --git a/docs/tutorials/flask_images/screen_02.png b/docs/tutorials/flask_images/screen_02.png
new file mode 100644
index 00000000..350aaa67
Binary files /dev/null and b/docs/tutorials/flask_images/screen_02.png differ
diff --git a/docs/tutorials/index.rst b/docs/tutorials/index.rst
index d3efc2b6..51c6f09a 100644
--- a/docs/tutorials/index.rst
+++ b/docs/tutorials/index.rst
@@ -1,3 +1,5 @@
+.. _tutorials:
+
Tutorials
=========
@@ -10,3 +12,5 @@ frameworks.
flask
aiohttp
asyncio
+
+.. disqus::
diff --git a/examples/miniapps/ghnav-flask/README.rst b/examples/miniapps/ghnav-flask/README.rst
index 5388989c..ca6b3a2c 100644
--- a/examples/miniapps/ghnav-flask/README.rst
+++ b/examples/miniapps/ghnav-flask/README.rst
@@ -81,7 +81,7 @@ The output should be something like:
.. code-block::
platform darwin -- Python 3.8.3, pytest-5.4.3, py-1.9.0, pluggy-0.13.1
- plugins: flask-1.0.0, cov-2.10.0, asyncio-0.14.0
+ plugins: flask-1.0.0, cov-2.10.0
collected 2 items
githubnavigator/tests.py .. [100%]
@@ -90,10 +90,10 @@ The output should be something like:
Name Stmts Miss Cover
----------------------------------------------------
githubnavigator/__init__.py 0 0 100%
- githubnavigator/application.py 8 0 100%
- githubnavigator/containers.py 11 0 100%
+ githubnavigator/application.py 11 0 100%
+ githubnavigator/containers.py 13 0 100%
githubnavigator/services.py 14 0 100%
- githubnavigator/tests.py 33 0 100%
+ githubnavigator/tests.py 32 0 100%
githubnavigator/views.py 7 0 100%
----------------------------------------------------
- TOTAL 73 0 100%
+ TOTAL 77 0 100%
diff --git a/examples/miniapps/ghnav-flask/githubnavigator/tests.py b/examples/miniapps/ghnav-flask/githubnavigator/tests.py
index fa36678c..f8ea3d87 100644
--- a/examples/miniapps/ghnav-flask/githubnavigator/tests.py
+++ b/examples/miniapps/ghnav-flask/githubnavigator/tests.py
@@ -43,6 +43,7 @@ def test_index(client, app):
response = client.get(url_for('index'))
assert response.status_code == 200
+ assert b'Results found: 2' in response.data
assert b'repo1-url' in response.data
assert b'repo1-name' in response.data
@@ -65,4 +66,4 @@ def test_index_no_results(client, app):
response = client.get(url_for('index'))
assert response.status_code == 200
- assert b'No search results' in response.data
+ assert b'Results found: 0' in response.data