<?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: Amazia Gur</title>
    <description>The latest articles on DEV Community by Amazia Gur (@amazia_gur_fd339831499743).</description>
    <link>https://dev.to/amazia_gur_fd339831499743</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4016069%2F9ee2cd62-04fb-42d8-868d-0a8ce50c2c25.jpg</url>
      <title>DEV Community: Amazia Gur</title>
      <link>https://dev.to/amazia_gur_fd339831499743</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/amazia_gur_fd339831499743"/>
    <language>en</language>
    <item>
      <title>Stop running a JVM just to mock an API in your CI pipeline</title>
      <dc:creator>Amazia Gur</dc:creator>
      <pubDate>Sun, 05 Jul 2026 10:55:21 +0000</pubDate>
      <link>https://dev.to/amazia_gur_fd339831499743/stop-running-a-jvm-just-to-mock-an-api-in-your-ci-pipeline-44i4</link>
      <guid>https://dev.to/amazia_gur_fd339831499743/stop-running-a-jvm-just-to-mock-an-api-in-your-ci-pipeline-44i4</guid>
      <description>&lt;p&gt;If you've set up WireMock in a CI pipeline before, you know the pattern: pull a Docker image with a full JVM in it, wait for it to boot, configure stubs via a REST API or a pile of JSON files, then tear it down. For a Python project, that's a second language runtime in your pipeline purely to answer &lt;code&gt;GET /users&lt;/code&gt; with a canned response.&lt;/p&gt;

&lt;p&gt;Mimicker is a Python-native alternative. It's a plain &lt;code&gt;pip install&lt;/code&gt;, it starts in-process or via a one-line CLI call, and it has no JVM, no native dependencies, and no heavy runtime — just two small pure-Python libraries (PyYAML for config, colorlog for output).&lt;/p&gt;

&lt;h2&gt;
  
  
  The Python DSL
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mimicker.mimicker&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;mimicker&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;get&lt;/span&gt;

&lt;span class="nf"&gt;mimicker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/hello&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;body&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello, World!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's a running mock server on port 8080. No config file, no separate process to manage if you don't want one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The same thing in YAML
&lt;/h2&gt;

&lt;p&gt;For when you want stubs defined outside your test code, useful if QA or frontend devs need to spin up a mock without touching Python:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# stubs.yaml&lt;/span&gt;
&lt;span class="na"&gt;routes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;GET&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/hello&lt;/span&gt;
    &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;200&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Hello, World!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mimicker serve &lt;span class="nt"&gt;--config&lt;/span&gt; stubs.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Where WireMock still wins
&lt;/h2&gt;

&lt;p&gt;WireMock is mature, has a huge feature set (request matching on nearly anything, record-and-playback, fault injection, a proper admin API), and if you're already in a JVM shop, it's a known quantity. Mimicker doesn't try to match that surface area — it's intentionally smaller.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where mimicker is a better fit
&lt;/h2&gt;

&lt;p&gt;You're testing a Python service, you don't want a second runtime in CI, and you want stub definitions your whole team can read without learning WireMock's JSON mapping format.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using it in CI
&lt;/h2&gt;

&lt;p&gt;There's an official GitHub Action:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mimickerhq/mimicker-action@v1&lt;/span&gt;
    &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;stubs/api.yaml&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run tests&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pytest&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It also ships something WireMock doesn't have out of the box: a stub coverage report. After your tests run, it tells you which stubs were actually hit, so if you delete an endpoint from the real API and forget to update the stub, you find out in CI instead of in production three weeks later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Mimicker coverage report&lt;/span&gt;
  &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always()&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bash ${{ steps.mock.outputs.report-script }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add &lt;code&gt;fail-on-unused: true&lt;/code&gt; and the job fails outright if a stub goes stale.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;Mimicker is at &lt;a href="https://github.com/mimickerhq/mimicker" rel="noopener noreferrer"&gt;github.com/mimickerhq/mimicker&lt;/a&gt;, docs at &lt;a href="https://mimickerhq.github.io/mimicker" rel="noopener noreferrer"&gt;mimickerhq.github.io/mimicker&lt;/a&gt;. It's still small — if you try it and something's missing for your use case, that's exactly the kind of issue I want to hear about.&lt;/p&gt;

</description>
      <category>python</category>
      <category>devops</category>
      <category>testing</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
