<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Iuliia Volkova</title>
    <description>The latest articles on DEV Community by Iuliia Volkova (@xnuinside).</description>
    <link>https://dev.to/xnuinside</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F222957%2F8dd70b8c-a27a-427a-846b-061e724f29de.png</url>
      <title>DEV Community: Iuliia Volkova</title>
      <link>https://dev.to/xnuinside</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/xnuinside"/>
    <language>en</language>
    <item>
      <title>Little bit of 'monkey patching'</title>
      <dc:creator>Iuliia Volkova</dc:creator>
      <pubDate>Sun, 31 May 2020 22:42:32 +0000</pubDate>
      <link>https://dev.to/xnuinside/little-bit-of-monkey-patching-send-common-used-variables-to-sanic-jinja2-in-one-place-2gcp</link>
      <guid>https://dev.to/xnuinside/little-bit-of-monkey-patching-send-common-used-variables-to-sanic-jinja2-in-one-place-2gcp</guid>
      <description>&lt;p&gt;&lt;strong&gt;Monkey Patching&lt;/strong&gt; - the way to change objects behaviour in runtime. The&lt;br&gt;
way that you can use to customize some third-party logic specially for&lt;br&gt;
your purposes.&lt;/p&gt;

&lt;p&gt;This is a pretty small article with an illustration case where Monkey&lt;br&gt;
Patching can be useful. One day I thought about how to avoid sending&lt;br&gt;
common used variables to Jinja2 templates in each route. And in Django,&lt;br&gt;
Flask and aiohttp-jinja2 and many others frameworks/libs for this exists&lt;br&gt;
&lt;strong&gt;context_processor&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Let’s imagine - you have a Web App with Sanic and Server Side Rendering&lt;br&gt;
Templates with Jinja2.  For example, you have a header with Menu, some&lt;br&gt;
logo, title - any information that is used on each page of your app. You&lt;br&gt;
want to define it in one place.&lt;/p&gt;

&lt;p&gt;In my case I need this in the process of work on the Gino-Admin panel.&lt;br&gt;
And I use Sanic &amp;amp; Sanic-Jinja2.&lt;/p&gt;

&lt;p&gt;I have something like this on each route:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;return jinja.render(
   "login.html", request, objects=cfg.models, url_prefix=cfg.URL_PREFIX,
)

return jinja.render(
   "db_drop.html",
   request,
   data=await count_elements_in_db(),
   objects=cfg.models,
   url_prefix=cfg.URL_PREFIX,
)

return jinja.render(
   "presets.html",
   request,
   presets_folder=cfg.presets_folder,
   presets=utils.get_presets()['presets'],
   objects=cfg.models,
   url_prefix=cfg.URL_PREFIX,
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And etc.&lt;/p&gt;

&lt;p&gt;As you see each time I send  &lt;code&gt;url_prefix=cfg.URL_PREFIX&lt;/code&gt;, prefix that&lt;br&gt;
used as a base route for admin panel and &lt;code&gt;objects=cfg.models&lt;/code&gt; - list of&lt;br&gt;
models that we render in Admin panel for add/edit/delete.&lt;/p&gt;

&lt;p&gt;I don’t like to duplicate code, also I want to add more customisation,&lt;br&gt;
like set custom title for admin panel in config and other things in the&lt;br&gt;
future. And sending all new common variables inside each route will be&lt;br&gt;
painful. So I need a way to provide these variables only once.&lt;/p&gt;

&lt;p&gt;Sanic-Jinja2 also has &lt;em&gt;context_processor&lt;/em&gt; arg but I tried a lot of things&lt;br&gt;
to send in it, and nothing works for me. I failed. Maybe I have the&lt;br&gt;
wrong hands &amp;amp; head.&lt;/p&gt;

&lt;p&gt;But I want this feature, so go on.&lt;/p&gt;
&lt;h2&gt;
  
  
  SanicJinja2.render
&lt;/h2&gt;

&lt;p&gt;To render all templates, the Sanic-JInja2 package uses the main method&lt;br&gt;
render(...)&lt;/p&gt;

&lt;p&gt;If you never used &lt;strong&gt;Sanic-Jinja2&lt;/strong&gt; to add it to Sanic app looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from sanic_jinja2 import SanicJinja2

jinja = SanicJinja2()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's it, after in routes you use it like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;return jinja.render(
   "presets.html",
   request,
   presets_folder=cfg.presets_folder,
   presets=utils.get_presets()['presets'],
   objects=cfg.models,
   url_prefix=cfg.URL_PREFIX,
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Okay. Time for monkey patching.&lt;/p&gt;

&lt;h2&gt;
  
  
  Main idea
&lt;/h2&gt;

&lt;p&gt;go inside the source code, check that part code you need &lt;code&gt;re-write&lt;/code&gt; -&lt;br&gt;
and patch with your own implementation that solves your pain.&lt;/p&gt;

&lt;p&gt;What I need?  I need to patch each response before page render with&lt;br&gt;
common context variables that are used in each template.&lt;/p&gt;

&lt;p&gt;If we jump in  SanicJinja2 source code we will see, that&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.google.com/url?q=https://github.com/lixxu/sanic-jinja2/blob/master/sanic_jinja2/__init__.py%23L143&amp;amp;sa=D&amp;amp;ust=1590967088522000"&gt;https://github.com/lixxu/sanic-jinja2/blob/master/sanic_jinja2/__init__.py#L143&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I need to change small method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def render(self, template, request, status=200, headers=None, **context):
    return html(
            self.render_string(template, request, **context),
            status=status,
            headers=headers,
        )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So I will define my own method. Let’s call it ‘custom_render’. I will&lt;br&gt;
just copy the paste base method - render and add into context all&lt;br&gt;
variables that I need.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def custom_render(
self, template, request, status=200, headers=None, **context
):
   context["admin_panel_title"] = cfg.name
   context["objects"] = cfg.models
   context["url_prefix"] = cfg.route
   context["admin_panel_version"] = __version__
   context["round_number"] = cfg.round_number
   return html(
       self.render_string(template, request, **context),
       status=status,
       headers=headers,
   )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now we need to ‘patch’ our target class &lt;strong&gt;SanicJinja2&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SanicJinja2.render = custom_render&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;So all the next code that will use this class after the line with&lt;br&gt;
&lt;code&gt;patch&lt;/code&gt; will call our custom method logic as the &lt;code&gt;render&lt;/code&gt; method of&lt;br&gt;
SanicJinja2 class.&lt;/p&gt;

&lt;p&gt;Beautiful freedom of Python. You have a lot of ways to solve your&lt;br&gt;
issues.&lt;/p&gt;

&lt;p&gt;Code samples in project repo:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.google.com/url?q=https://github.com/xnuinside/gino-admin/blob/master/gino_admin/config.py%23L20&amp;amp;sa=D&amp;amp;ust=1590967088525000"&gt;https://github.com/xnuinside/gino-admin/blob/master/gino_admin/config.py#L20&lt;/a&gt; &lt;/p&gt;

</description>
      <category>python</category>
      <category>sanic</category>
      <category>example</category>
      <category>jinja2</category>
    </item>
    <item>
      <title>Integration tests for bunch of services with Pytest &amp; Docker Compose</title>
      <dc:creator>Iuliia Volkova</dc:creator>
      <pubDate>Sun, 17 May 2020 17:32:12 +0000</pubDate>
      <link>https://dev.to/xnuinside/integration-tests-for-bunch-of-services-with-pytest-docker-compose-j5i</link>
      <guid>https://dev.to/xnuinside/integration-tests-for-bunch-of-services-with-pytest-docker-compose-j5i</guid>
      <description>&lt;h3&gt;
  
  
  Table Of Contents
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Preface&lt;/li&gt;
&lt;li&gt;
Introduction (Tools | An idea)&lt;/li&gt;
&lt;li&gt;Docker-Compose &amp;amp; Dockerfiles&lt;/li&gt;
&lt;li&gt;Create test-docker-compose.yml&lt;/li&gt;
&lt;li&gt;Pytest Plugin&lt;/li&gt;
&lt;li&gt;Define conftest.py&lt;/li&gt;
&lt;li&gt;Create Tests Module&lt;/li&gt;
&lt;li&gt;Run tests&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Preface &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Hi! This is my first article on dev.to. Previously I wrote Tutorials on Medium (link must be somewhere in profile). Today I want to share a guide on how to set up integration tests for a bunch of services. Last month I worked on a similar task and for some members of the team the result looked like something new. I thought that maybe it would make sense to write a quick guide about it.&lt;/p&gt;

&lt;p&gt;Besides, I really need to write tests for &lt;a href="https://github.com/xnuinside/gino-admin"&gt;https://github.com/xnuinside/gino-admin&lt;/a&gt;. Of course, I need a set of different tests, but today I will prepare a set up for tests, that will check examples are run correctly with new changes in "Gino Admin" code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Introduction &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  In guide I will use: &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Python &lt;/li&gt;
&lt;li&gt;pytest&lt;/li&gt;
&lt;li&gt;pytest-docker-compose&lt;/li&gt;
&lt;li&gt;requests 
(we can easily use something asyncio httpx or aiohttp, but in this case no make sense, because I will not add any concurrency ro tests in this tutorial, so the run one-by-one)&lt;/li&gt;
&lt;li&gt;docker &amp;amp; docker compose&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Main idea:  &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;You have a project with several microservices or services (does not matter in this context) and DB. And you need to run tests on this infrastructure, to be sure that components works together.&lt;/p&gt;

&lt;h4&gt;
  
  
  My Demo Project setup:
&lt;/h4&gt;

&lt;p&gt;For the tutorial I will take &lt;code&gt;fastapi_as_main_app&lt;/code&gt; from Gino Admin examples, because it contains Web App on FastAPI, Admin panel &amp;amp; DB PostgreSQL. Source code of this tiny project here: &lt;a href="https://github.com/xnuinside/gino-admin/tree/master/examples/fastapi_as_main_app"&gt;https://github.com/xnuinside/gino-admin/tree/master/examples/fastapi_as_main_app&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Tutorial  &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;At the beginning we need 2 things: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;up &amp;amp; run our services &lt;/li&gt;
&lt;li&gt;be sure that they are see each other and can connect &lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Docker-Compose &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;If in 2020 you still don’t use/try docker-compose - just google tutorials about it and give it a chance. It’s really irreplaceable in case of several-services backends at least for dev and test envs.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For up&amp;amp;run we will use &lt;strong&gt;Docker Compose&lt;/strong&gt;, as you might have guessed.&lt;/p&gt;

&lt;p&gt;Before start work on &lt;strong&gt;docker-compose.yml&lt;/strong&gt; file you need to prepare &lt;strong&gt;Dockerfiles&lt;/strong&gt; for services. First of all, let’s take a look on my source structure:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WJTwDhDQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/cqmogmr0r2mhwpljy319.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WJTwDhDQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/cqmogmr0r2mhwpljy319.png" alt="Project Source Structure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It would be a bad idea to mix 'take &amp;amp; play' examples with tests, so I will put all files that needed for tests inside &lt;code&gt;tests/&lt;/code&gt; dir.&lt;/p&gt;

&lt;p&gt;Let’s create a folder &lt;code&gt;integration_tests/&lt;/code&gt; and inside create a &lt;code&gt;docker/&lt;/code&gt; folder, where we will store all &lt;strong&gt;Dockerfiles&lt;/strong&gt; that I will use for integration tests. Now I will create 2 Dockerfiles - one for Main App, one for Admin Panel. And I will have this structure in tests folder:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--j-FLOGWw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/q2gquycgvj3yue8vhwwu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--j-FLOGWw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/q2gquycgvj3yue8vhwwu.png" alt="Tests Folder Structure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Docker context &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;Now, I need to pay attention to the Docker context. Because I need to have access to the &lt;code&gt;examples/&lt;/code&gt; folder in Dockerfile (and as you know docker does not allow access any paths outside Docker context) my &lt;strong&gt;Docker context&lt;/strong&gt; will be а main &lt;code&gt;gino_admin/&lt;/code&gt; folder that contains 'examples'. So when I define Dockerfiles I remember, that my workdir will be 'gino_admin' folder, not directory 'docker/' where Dockerfiles are placed in.&lt;/p&gt;

&lt;p&gt;In my case there will be two Docker files - one for the admin panel, one for the main app. PostgreSQL will be builded from the official image.&lt;/p&gt;

&lt;h4&gt;
  
  
  Dockerfiles  &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;Pretty simple Dockerfiles. Install requirements, copy source code, run. &lt;/p&gt;

&lt;p&gt;For &lt;em&gt;admin panel&lt;/em&gt; I also need to add &lt;code&gt;gino_admin&lt;/code&gt; sources and install from them inside, because this is what I test - code, not releases from PyPi:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
And for Main App:&lt;br&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h4&gt;
  
  
  Create test-docker-compose.yml &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;Let’s go and create a &lt;code&gt;test-docker-compose.yml&lt;/code&gt; file with all our services that are needed for a correct test. &lt;/p&gt;

&lt;p&gt;Go into &lt;code&gt;tests/integration_tests/&lt;/code&gt;. Create &lt;code&gt;test-docker-compose.yml&lt;/code&gt;. Pay attention to &lt;strong&gt;Context&lt;/strong&gt; and &lt;strong&gt;Dockerfile path&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Our &lt;code&gt;test-docker-compose.yml&lt;/code&gt; will be:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;I need to set var &lt;code&gt;DB_HOST=postgres&lt;/code&gt; because it uses inside code (here:) to decide that PostgreSQL host connects. If it runs inside docker-compose cluster - host &lt;code&gt;postgres&lt;/code&gt;, if not  - &lt;code&gt;localhost&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Cool. Now time to run:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ docker-compose -f test-docker-compose.yml up --build&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And we got:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--84N_pXPL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/xf2fo6qufxsdkdhhi7e4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--84N_pXPL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/xf2fo6qufxsdkdhhi7e4.png" alt="Connection Error"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Aha, we set &lt;code&gt;depends_on&lt;/code&gt; but anyway see an error &lt;code&gt;Connection refused&lt;/code&gt; in services. Because servers try to connect to DB before it is really up. &lt;code&gt;depends_on&lt;/code&gt; only waits for the docker container run, but it does not know anything about the real start of the server/process inside the container. &lt;/p&gt;

&lt;h3&gt;
  
  
  Wait-for script &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;We need to wait for the DB before running our services. For this exists a &lt;code&gt;wait-for&lt;/code&gt; pattern-script. It can bash, python, any would you like. Idea of this script - wait till you got 'success' on some condition. &lt;/p&gt;

&lt;p&gt;In our case we need to wait till &lt;code&gt;PostgresDB&lt;/code&gt; will be ready to accept connections. &lt;/p&gt;

&lt;p&gt;Let’s create &lt;code&gt;wait_for.py&lt;/code&gt;. We will place it in same folder near compose .yml file &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--35RfUNSt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/cadlh967nwwo2p8vu7gy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--35RfUNSt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/cadlh967nwwo2p8vu7gy.png" alt="Tests Folder Structure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Content of the script will be very simple, to check DB connections I will use the same libraries that already exist as dependencies, but in your case you can use anything you want. Most simple &amp;amp; popular way - with &lt;code&gt;psycopg2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I will use &lt;code&gt;Gino&lt;/code&gt;, because as I said I use it anyway in App:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Not much logic - just try to connect, if error sleep 8 sec, try again. &lt;/p&gt;

&lt;p&gt;Now we need to modify &lt;strong&gt;Dockerfiles&lt;/strong&gt;, before running servers we need to run this script. And when it returns 0 - run servers. &lt;/p&gt;

&lt;p&gt;Change our last line in main app Dockerfile to:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;COPY ../../tests/wait_for.py /wait_for.py&lt;br&gt;
CMD python /wait_for.py &amp;amp;&amp;amp; uvicorn main:app  --host 0.0.0.0 --port 5050&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And in admin panel to:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;COPY tests/integration_tests/wait_for.py /wait_for.py&lt;br&gt;
CMD python /wait_for.py &amp;amp;&amp;amp; python admin.py&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; same way you can run any pre-setup action that you need to make your service works. &lt;/p&gt;

&lt;p&gt;Now run the cluster again with:&lt;br&gt;
&lt;code&gt;$ docker-compose -f test-docker-compose.yml up --build&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And we get a successful result. All services up &amp;amp; work. &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9fEotu6_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/7o75emdgzznt0d4ig3lf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9fEotu6_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/7o75emdgzznt0d4ig3lf.png" alt="Servers Up"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Great. We have a test cluster, now we need something that allows a run test inside this cluster.&lt;/p&gt;
&lt;h3&gt;
  
  
  Pytest plugin for Docker Compose &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;If you never worked with &lt;strong&gt;Pytest&lt;/strong&gt; make sense first of all take a look at official documentation and some tutorials. At least you need to understand that it is &lt;strong&gt;fixtures&lt;/strong&gt;  - &lt;a href="https://docs.pytest.org/en/latest/fixture.html"&gt;https://docs.pytest.org/en/latest/fixture.html&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Exist 3 different plugins for &lt;strong&gt;Pytest&lt;/strong&gt; to run tests on docker-compose infrastructure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/pytest-docker-compose/pytest-docker-compose"&gt;https://github.com/pytest-docker-compose/pytest-docker-compose&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/avast/pytest-docker"&gt;https://github.com/avast/pytest-docker&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/lovelysystems/lovely-pytest-docker"&gt;https://github.com/lovelysystems/lovely-pytest-docker&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I checked all 3, but at the end of the day stop on &lt;code&gt;pytest-docker-compose&lt;/code&gt; . It works for me better than others in scope of speed and usage clearness.&lt;/p&gt;

&lt;p&gt;Let’s start with packages installation:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ pip install pytest&lt;br&gt;
$ pip install pytest-docker-compose&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Define conftest.py &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;Now, let’s create our &lt;code&gt;conftest.py&lt;/code&gt;&lt;br&gt;
 (&lt;a href="https://docs.pytest.org/en/2.7.3/plugins.html"&gt;https://docs.pytest.org/en/2.7.3/plugins.html&lt;/a&gt;) for pytest where we will define our custom path to docker-compose file that we use to run tests and plugin.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;And right now we finished prepare our common infrastructure. &lt;/p&gt;

&lt;p&gt;Next setup our first test module.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create Tests Module &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;As you remember I have several examples and each of them - set of services, that works with DB. For each example, I will have own test module and own fixtures.&lt;/p&gt;

&lt;h3&gt;
  
  
  Services Fixtures
&lt;/h3&gt;

&lt;p&gt;Create our first test_module: I will keep naming consistent and call it &lt;code&gt;test_fastapi_as_main_app_example.py&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now our tests folder looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hFfEK0zJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/iw1rg2e4c74b7j3gxdce.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hFfEK0zJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/iw1rg2e4c74b7j3gxdce.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Inside &lt;code&gt;test_fastapi_as_main_app_example.py&lt;/code&gt; first of all we need to define fixtures with our services: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To check that they up &amp;amp; run success&lt;/li&gt;
&lt;li&gt;To get their uri, that we will use in tests&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;That need to pay attention:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Module_scoped_container_getter&lt;/code&gt; - this is a special fixture, provided by &lt;code&gt;pytest-docker-compose&lt;/code&gt; plugin. I use &lt;code&gt;Module_scoped_container_getter&lt;/code&gt;, because each of my examples - a set of separate groups of apps with their own DB schema - for each module I will need to drop DB Tables and create them for a concrete example that I test in the module. &lt;/p&gt;

&lt;p&gt;Plugin provides 4 different fixtures that define behaviour about how often build and run containers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Function_scoped_container_getter&lt;/li&gt;
&lt;li&gt;Class_scoped_container_getter&lt;/li&gt;
&lt;li&gt;Module_scoped_container_getter&lt;/li&gt;
&lt;li&gt;Session_scoped_container_getter&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next pay attention to line:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;service = module_scoped_container_getter.get("fastapi_main_app_main").network_info[0]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;.get(...)&lt;/code&gt; method you need to provide a service name as it is defined in docker-compose yml file. &lt;/p&gt;

&lt;p&gt;Now let's define 2 simple tests - check '/' page and assert that for both services status code 200. Add to the same &lt;code&gt;test_fastapi_as_main_app_example.py&lt;/code&gt; file: &lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Time to run tests.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to run tests &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;To run the test you have 2 possible ways.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First way&lt;/strong&gt; - &lt;code&gt;build &amp;amp; up &amp;amp; run&lt;/code&gt; with &lt;code&gt;one command&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pytest . --docker-compose=test-docker-compose.yml -v
# will build and run docker compose &amp;amp; execute the tests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Second way&lt;/strong&gt; allow you to reduce time in process of tests creating/debugging because you don’t rebuild each run containers.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker-compose -f test-docker-compose.yml up --build
# build &amp;amp; run test cluster
# when in new terminal window:
pytest . --docker-compose=test-docker-compose.yml --docker-compose-no-build --use-running-containers -v 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Choose any would you like and run test.&lt;/p&gt;

&lt;p&gt;And we got green result:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gI3yKuLc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/lb1ljui53jqoukblpr1a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gI3yKuLc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/lb1ljui53jqoukblpr1a.png" alt="First tests passed"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Great, all works. Services up and we can use them from tests.&lt;/p&gt;
&lt;h3&gt;
  
  
  Auth fixtures
&lt;/h3&gt;

&lt;p&gt;Now let’s add more fixtures. I want to test the REST API of the admin panel, but to make API calls I need to get an auth token first. So I need to add a fixture with an auth step.&lt;/p&gt;

&lt;p&gt;Also, I need to upload a preset on DB - some Initial Data Set. Special for this in Gino Admin exist feature &lt;strong&gt;Presets&lt;/strong&gt;, that allow defining a list of CSV files that will be uploaded to DB. You can have multiple different DB Presets and load them with drop db or  just insert to existing tables - as you want. &lt;/p&gt;

&lt;p&gt;So I will define 2 fixtures - 1 to auth, 2 to upload preset&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;As you see you can use one fixtures in another. &lt;/p&gt;

&lt;p&gt;Add two more test: one that will use our new fixture 'initdb', second only 'admin_auth_headers'. &lt;/p&gt;

&lt;p&gt;I will write a test for &lt;em&gt;Main App&lt;/em&gt; endpoint &lt;code&gt;/users&lt;/code&gt;. This endpoint returns count of users in DB. So &lt;code&gt;/users&lt;/code&gt; endpoint must returns {"count_users": 5} based on data that I load with Preset. &lt;/p&gt;

&lt;p&gt;And test for &lt;code&gt;/api/drop_db&lt;/code&gt; endpoint of Admin Panel.&lt;/p&gt;

&lt;p&gt;Add tests:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Pay attention to initdb fixture, we don’t use it in method call, but we need to call initdb fixture, because for this test we need to have Data in DB.&lt;/p&gt;

&lt;p&gt;Because our initdb fixture has scope=”module” it means that it will be executed only once per module, if you want recreate db for each test - change it to “function”&lt;/p&gt;

&lt;p&gt;Run tests &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NiAI-RyG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/vl1t4q2cc0x7ypegx48e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NiAI-RyG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/vl1t4q2cc0x7ypegx48e.png" alt="Green Tests"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Awesome. That's it. &lt;/p&gt;

&lt;p&gt;In my case next steps was - add more modules and more tests for each example. And source code with tests samples you can find here: &lt;a href="https://github.com/xnuinside/gino-admin/tree/master/tests/integration_tests"&gt;https://github.com/xnuinside/gino-admin/tree/master/tests/integration_tests&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In you case maybe need to use scope="session" if you care about tests speed and you code don't have sides effects or maybe opposite you need scope="functions" - check more about it in Pytest docs. &lt;/p&gt;

&lt;p&gt;Such integrations tests very helpful when you have 4-5 services that call each other and you need to be sure that they works together correct. &lt;/p&gt;

&lt;p&gt;I hope it will be useful for someone. If you will see any errors - feel free to comment, I will try to fix them fast.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>python</category>
      <category>docker</category>
      <category>testing</category>
    </item>
  </channel>
</rss>
