<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Chirag Choudhary]]></title><description><![CDATA[Chirag Choudhary]]></description><link>https://blog.chiragc.com</link><generator>RSS for Node</generator><lastBuildDate>Tue, 06 Oct 2026 12:31:29 GMT</lastBuildDate><atom:link href="https://blog.chiragc.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[How We Mastered Unit Testing at Our Startup]]></title><description><![CDATA[Problem Statement:
At a startup where I joined as the 4th engineer, we faced a production issue every other weekend, which would be every 4th release, primarily due to new team members lacking context on different workflows. Adding documentation for ...]]></description><link>https://blog.chiragc.com/how-we-mastered-unit-testing-at-our-startup</link><guid isPermaLink="true">https://blog.chiragc.com/how-we-mastered-unit-testing-at-our-startup</guid><category><![CDATA[unit testing]]></category><category><![CDATA[unit test]]></category><category><![CDATA[unit tests]]></category><category><![CDATA[Python]]></category><category><![CDATA[Django]]></category><dc:creator><![CDATA[Chirag Choudhary]]></dc:creator><pubDate>Sat, 01 Jun 2024 18:30:00 GMT</pubDate><content:encoded><![CDATA[<h2 id="heading-problem-statement">Problem Statement:</h2>
<p>At a startup where I joined as the 4th engineer, we faced a production issue every other weekend, which would be every 4th release, primarily due to new team members lacking context on different workflows. Adding documentation for the product and code was necessary but insufficient to ensure quality.</p>
<h2 id="heading-solution">Solution:</h2>
<p>Given our team size of 6-7 engineers, I identified unit testing as the most effective solution. Consequently, I introduced the first set of unit tests for the backend and <a target="_blank" href="https://blog.chiragc.com/add-django-coverage-and-quality-pipelines-in-gitlab">created testing pipelines on gitlab</a>. Created a plan around the same considering the constraint that It was also essential to onboard engineers to this new process with minimal impact on KTLO (Keeping the Lights On), ensuring no disruption to planned projects and timelines.</p>
<h2 id="heading-the-plan">The plan:</h2>
<ul>
<li><p>I received a go ahead from the Head of Engineering for this.</p>
</li>
<li><p>I devised a phased approach to facilitate a smooth transition:</p>
<ol>
<li><p>Initial Phase: Require at least one test case for a merge request (MR) to be approved.</p>
</li>
<li><p>Intermediate Phase: Increase the requirement to a few test cases for MR approval.</p>
</li>
<li><p>Advanced Phase: Ensure all new functions, classes, and APIs are covered with test cases.</p>
</li>
<li><p>Final Phase: Mandate that all code changes are covered with test cases.</p>
</li>
</ol>
</li>
</ul>
<h2 id="heading-execution">Execution</h2>
<p>Since I was reviewing most of the MRs soon into the company, it was easy for me to ask the developers to add test cases. I provided references on how to do this with the test cases I had added and sometimes sat with the developers to guide them through the process. This approach was mostly effective. However, about a month into the process, a developer faced a significant challenge. He had a substantial set of changes dependent on a lot of existing code, which required writing factories for numerous models to create a few test cases. This raised the question of whether it was worth investing time to add test cases immediately or defer them. In cases when you are trying to create a mindset shift or a change in process, it’s worth having an example of going above &amp; beyond to be ingrained in the team's culture, so I collaborated with them to ensure this was done.</p>
<h2 id="heading-progress-and-impact-on-the-codebase">Progress and Impact on the Codebase:</h2>
<p>The codebase was built over four years by three engineers, before the initially had about 28% test coverage since Python unit testing assumes coverage of function and class definitions. In the first quarter, much of the effort went into creating the base and factories, reaching approximately 35% coverage.</p>
<p>In the second quarter, we started seeing significant improvements. The increased emphasis on unit tests and the detection of breaking code changes helped us achieve about 45% coverage. Over the next two quarters, we continued to make progress, achieving around 10% and 7% additional coverage, respectively, bringing us to 62% coverage after one year.</p>
<p>While the percentage coverage increased gradually, we focused on improving the quality of the test cases themselves, covering more scenarios, and adding API integration tests. In the following 1.5 years, we reached 78% coverage, resulting in a fairly stable backend for the product.</p>
<p>I am executing a similar plan at another b2b software startup with a larger engineering team. Would share new learnings from that as a separate blog post.</p>
]]></content:encoded></item><item><title><![CDATA[Add Django Coverage and Quality pipelines in Gitlab]]></title><description><![CDATA[Introduction
If you have a Django project and you want to leverage Gitlab's pipelines to see your test cases running or see the code coverage percentage. This article will guide you step by step.
Code Coverage setup
For the code coverage you need to ...]]></description><link>https://blog.chiragc.com/add-django-coverage-and-quality-pipelines-in-gitlab</link><guid isPermaLink="true">https://blog.chiragc.com/add-django-coverage-and-quality-pipelines-in-gitlab</guid><category><![CDATA[Django]]></category><category><![CDATA[Git]]></category><category><![CDATA[GitLab]]></category><category><![CDATA[Testing]]></category><dc:creator><![CDATA[Chirag Choudhary]]></dc:creator><pubDate>Tue, 02 May 2023 19:24:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1683401948752/cf83e2ee-5b96-44ad-8443-5c86c73901f7.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>If you have a Django project and you want to leverage Gitlab's pipelines to see your test cases running or see the code coverage percentage. This article will guide you step by step.</p>
<h3 id="heading-code-coverage-setup">Code Coverage setup</h3>
<p>For the code coverage you need to create a gitlab.yml file in your repo &amp; add the following code:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">coverage:</span>
    <span class="hljs-attr">stage:</span> <span class="hljs-string">test</span>
    <span class="hljs-attr">only:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">merge_requests</span>
    <span class="hljs-attr">services:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">mysql:5.7</span>
    <span class="hljs-attr">before_script:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">python3.7</span> <span class="hljs-string">-m</span> <span class="hljs-string">pip</span> <span class="hljs-string">install</span> <span class="hljs-string">--upgrade</span> <span class="hljs-string">pip</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">python3.7</span> <span class="hljs-string">-V</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">pip3.7</span> <span class="hljs-string">install</span> <span class="hljs-string">-r</span> <span class="hljs-string">requirements.txt</span>
    <span class="hljs-attr">script:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">coverage</span> <span class="hljs-string">run</span> <span class="hljs-string">-m</span> <span class="hljs-string">pytest</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">coverage</span> <span class="hljs-string">run</span> <span class="hljs-string">manage.py</span> <span class="hljs-string">test</span>
</code></pre>
<p>This is assuming that you are using MySQL service for the DB, if you use a different DB or don’t use one feel free to remove it.</p>
<p>With this you should be able to see the pipelines running &amp; the logs below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1682981368684/e2041ea9-1813-4c32-ad7c-a55d9c694181.png" alt class="image--center mx-auto" /></p>
<p>But wait, where is the coverage percentage?</p>
<p>For that, we need to enable the coverage report with <code>coverage report -m</code></p>
<p>This would help you see the coverage of each file</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1682981460243/5976011b-86ce-410f-b955-7ec00d4bf1c4.png" alt class="image--center mx-auto" /></p>
<p>Hmm… it is good but hard to read. Let’s generate the report in HTML, make it public  &amp; export it to GitLab's artifacts:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">coverage:</span>
    <span class="hljs-attr">stage:</span> <span class="hljs-string">test</span>
    <span class="hljs-attr">only:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">merge_requests</span>
    <span class="hljs-attr">services:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">mysql:5.7</span>
    <span class="hljs-attr">before_script:</span>
          <span class="hljs-bullet">-</span> <span class="hljs-string">python3.7</span> <span class="hljs-string">-m</span> <span class="hljs-string">pip</span> <span class="hljs-string">install</span> <span class="hljs-string">--upgrade</span> <span class="hljs-string">pip</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">python3.7</span> <span class="hljs-string">-V</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">pip3.7</span> <span class="hljs-string">install</span> <span class="hljs-string">-r</span> <span class="hljs-string">requirements.txt</span>
    <span class="hljs-attr">script:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">coverage</span> <span class="hljs-string">run</span> <span class="hljs-string">-m</span> <span class="hljs-string">pytest</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">coverage</span> <span class="hljs-string">run</span> <span class="hljs-string">manage.py</span> <span class="hljs-string">test</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">coverage</span> <span class="hljs-string">report</span> <span class="hljs-string">-m</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">coverage</span> <span class="hljs-string">html</span>
    <span class="hljs-attr">artifacts:</span>
        <span class="hljs-attr">paths:</span>
            <span class="hljs-bullet">-</span> <span class="hljs-string">htmlcov/</span>
    <span class="hljs-attr">when:</span> <span class="hljs-string">always</span>

<span class="hljs-attr">pages:</span>
    <span class="hljs-attr">stage:</span> <span class="hljs-string">coverage</span>
    <span class="hljs-attr">dependencies:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">coverage</span>
    <span class="hljs-attr">script:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">mv</span> <span class="hljs-string">htmlcov/</span> <span class="hljs-string">public/</span>
    <span class="hljs-attr">artifacts:</span>
        <span class="hljs-attr">paths:</span>
            <span class="hljs-bullet">-</span> <span class="hljs-string">public/</span>
    <span class="hljs-attr">when:</span> <span class="hljs-string">always</span>
    <span class="hljs-attr">only:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">merge_requests</span>
</code></pre>
<p>Please note that we are only running the pipelines when a merge request is raised or a change is made. Not after the MR is merged.</p>
<p>This helps us see the job artifacts with line by line covereage for each merge request.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1682981583452/e8d0bb51-b957-41ac-ae24-439172577e87.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1682981607155/5416ae1a-9b6e-4dba-80d1-fbbca3602d7a.png" alt class="image--center mx-auto" /></p>
<p>So this is a lot of clicks to see the coverage, let’s get it parsed by cobertura (fun fact! It's Spanish for coverage) &amp; into the GitLab UI. Let’s update the gitlab.yml, we are adding the xml report &amp; cobertura specific report.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">coverage:</span>
    <span class="hljs-attr">stage:</span> <span class="hljs-string">test</span>
    <span class="hljs-attr">only:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">merge_requests</span>
    <span class="hljs-attr">services:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">mysql:5.7</span>
    <span class="hljs-attr">before_script:</span>
          <span class="hljs-bullet">-</span> <span class="hljs-string">python3.7</span> <span class="hljs-string">-m</span> <span class="hljs-string">pip</span> <span class="hljs-string">install</span> <span class="hljs-string">--upgrade</span> <span class="hljs-string">pip</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">python3.7</span> <span class="hljs-string">-V</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">pip3.7</span> <span class="hljs-string">install</span> <span class="hljs-string">-r</span> <span class="hljs-string">requirements.txt</span>
    <span class="hljs-attr">script:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">coverage</span> <span class="hljs-string">run</span> <span class="hljs-string">-m</span> <span class="hljs-string">pytest</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">coverage</span> <span class="hljs-string">run</span> <span class="hljs-string">manage.py</span> <span class="hljs-string">test</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">coverage</span> <span class="hljs-string">report</span> <span class="hljs-string">-m</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">coverage</span> <span class="hljs-string">html</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">coverage</span> <span class="hljs-string">xml</span>
    <span class="hljs-attr">artifacts:</span>
        <span class="hljs-attr">paths:</span>
            <span class="hljs-bullet">-</span> <span class="hljs-string">htmlcov/</span>
        <span class="hljs-attr">reports:</span>
          <span class="hljs-attr">cobertura:</span> <span class="hljs-string">coverage.xml</span>
    <span class="hljs-attr">when:</span> <span class="hljs-string">always</span>

<span class="hljs-attr">pages:</span>
    <span class="hljs-attr">stage:</span> <span class="hljs-string">coverage</span>
    <span class="hljs-attr">dependencies:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">coverage</span>
    <span class="hljs-attr">script:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">mv</span> <span class="hljs-string">htmlcov/</span> <span class="hljs-string">public/</span>
    <span class="hljs-attr">artifacts:</span>
        <span class="hljs-attr">paths:</span>
            <span class="hljs-bullet">-</span> <span class="hljs-string">public/</span>
    <span class="hljs-attr">when:</span> <span class="hljs-string">always</span>
    <span class="hljs-attr">only:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">merge_requests</span>
</code></pre>
<p>We need to then configure the Gitlab repo’s settings &gt;  CI/CD</p>
<p><a target="_blank" href="https://gitlab.com/codebards/uplevel/-/settings/ci_cd">https://gitlab.com/codebards/uplevel/-/settings/ci_cd</a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1682981709756/13f73648-96fc-4049-b553-1702cb29208a.png" alt class="image--center mx-auto" /></p>
<p>With this you should be able to see the coverage for each merge request:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1682981754449/05e3496a-3a17-4ab9-9677-4d57adae4d29.png" alt class="image--center mx-auto" /></p>
<p>References:</p>
<p><a target="_blank" href="https://docs.gitlab.com/ee/ci/unit_test_reports.html">https://docs.gitlab.com/ee/ci/unit_test_reports.html</a></p>
<p><a target="_blank" href="https://docs.gitlab.com/ee/user/project/merge_requests/test_coverage_visualization.html">https://docs.gitlab.com/ee/user/project/merge_requests/test_coverage_visualization.html</a><br /><a target="_blank" href="https://stackoverflow.com/a/56675636/2084765">https://stackoverflow.com/a/56675636/2084765</a></p>
<h3 id="heading-code-quality">Code Quality</h3>
<p>For adding a code quality pipeline in your repo add the following in the Gitlab.yml</p>
<pre><code class="lang-yaml"><span class="hljs-attr">code_quality:</span>
   <span class="hljs-attr">rules:</span>
     <span class="hljs-bullet">-</span> <span class="hljs-attr">if:</span> <span class="hljs-string">'$CODE_QUALITY_DISABLED'</span>
       <span class="hljs-attr">when:</span> <span class="hljs-string">never</span>
     <span class="hljs-bullet">-</span> <span class="hljs-attr">if:</span> <span class="hljs-string">'$CI_PIPELINE_SOURCE == "merge_request_event"'</span> <span class="hljs-comment"># Run code quality job in merge request pipelines</span>
     <span class="hljs-bullet">-</span> <span class="hljs-attr">if:</span> <span class="hljs-string">'$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'</span>      <span class="hljs-comment"># Run code quality job in pipelines on the master branch (but not in other branch pipelines)</span>
     <span class="hljs-bullet">-</span> <span class="hljs-attr">if:</span> <span class="hljs-string">'$CI_COMMIT_TAG'</span>                               <span class="hljs-comment"># Run code quality job in pipelines for tags</span>
   <span class="hljs-attr">artifacts:</span>
     <span class="hljs-attr">paths:</span> [<span class="hljs-string">gl-code-quality-report.json</span>]
</code></pre>
<p>Create a codeclimate.yml file in your repo &amp; add the following content</p>
<pre><code class="lang-yaml"><span class="hljs-attr">plugins:</span>
  <span class="hljs-attr">pep8:</span>
    <span class="hljs-attr">enabled:</span> <span class="hljs-literal">true</span>
</code></pre>
<p>Reference: <a target="_blank" href="https://docs.gitlab.com/ee/user/project/merge_requests/code_quality.html">https://docs.gitlab.com/ee/user/project/merge_requests/code_quality.html</a></p>
]]></content:encoded></item></channel></rss>