<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged unit-testing</title>
<link>https://coderlegion.com/tag/unit-testing</link>
<description>Powered by Question2Answer</description>
<item>
<title>No More Fake DOM: Testing Library Unit Tests in the Real Browser</title>
<link>https://coderlegion.com/25909/no-more-fake-dom-testing-library-unit-tests-in-the-real-browser</link>
<description>&lt;p&gt;Every Testing Library test you have written runs against a simulated DOM. You know this. You accepted it years ago, along with the small pile of things that come with it: no real layout, nothing ever drawn on a screen, &lt;code&gt;jsdom&lt;/code&gt; throwing on APIs it does not implement, and the quiet suspicion that a passing test and a working component are not quite the same claim.&lt;/p&gt;
&lt;p&gt;I co-maintain &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.npmjs.com/package/twd-js&quot;&gt;twd-js&lt;/a&gt;, which runs tests inside your actual dev server. It was built for flow testing: visit a route, click through the app, assert on what the user sees. Component testing was the thing it did not do, and I said so in print when I &lt;a rel=&quot;nofollow&quot; href=&quot;https://dev.to/kevinccbsg/in-browser-testing-vitest-browser-mode-and-twd-side-by-side-1i3j&quot;&gt;compared it to Vitest Browser Mode&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Then I tried calling &lt;code&gt;render()&lt;/code&gt; inside a TWD test, mostly to see what would break.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;import { render, screen, cleanup } from &quot;@testing-library/react&quot;;
import { describe, it, afterEach } from &quot;twd-js/runner&quot;;
import { AppProvider } from &quot;@/context/AppContext&quot;;
import { twd } from &quot;twd-js&quot;;
import { Add } from &quot;../Add&quot;;
import { componentHost, restorePage } from &quot;@/twd-tests/support/componentHost&quot;;

describe(&quot;Add Component&quot;, () =&amp;gt; {
  afterEach(() =&amp;gt; {
    cleanup();
    restorePage();
  });

  it(&quot;renders the Add component&quot;, () =&amp;gt; {
    // componentHost() is a blank div on an empty page. More on it below.
    render(&amp;lt;AppProvider&amp;gt;&amp;lt;Add /&amp;gt;&amp;lt;/AppProvider&amp;gt;, { container: componentHost() });

    twd.should(screen.getByText(&quot;Add Item&quot;), &quot;be.visible&quot;);
  });
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nothing broke. The component mounts into the page, the sidebar shows it running, and the assertion checks an element that exists in a real browser. Same Testing Library API, no fake DOM under it.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/gj02099nimid4kw24kaz.png&quot; alt=&quot;component test in an actual browser&quot;&gt;&lt;/p&gt;
&lt;p&gt;That &lt;code&gt;AppProvider&lt;/code&gt; is the real one, not a test double. &lt;code&gt;Add&lt;/code&gt; uses a hook that reads from context and posts to an API, and in a real browser both of those work, so there is nothing to stand in for. That turns out to matter more than the missing jsdom.&lt;/p&gt;
&lt;h3 id=&quot;why-this-works-at-all&quot;&gt;Why this works at all&lt;/h3&gt;
&lt;p&gt;Testing Library was never tied to jsdom. &lt;code&gt;@testing-library/react&lt;/code&gt; renders a component into a DOM node and &lt;code&gt;@testing-library/dom&lt;/code&gt; queries it. jsdom is just the DOM most people hand it. Give it a real one and the same code runs, except now the component is actually on a screen, with a real size, a real position, and your CSS applied to it.&lt;/p&gt;
&lt;p&gt;TWD already runs inside your app in the browser, so the real DOM is right there. &lt;code&gt;render()&lt;/code&gt; uses it.&lt;/p&gt;
&lt;h3 id=&quot;the-setup&quot;&gt;The setup&lt;/h3&gt;
&lt;p&gt;One helper, and no changes to your app.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;render()&lt;/code&gt; appends its container to &lt;code&gt;document.body&lt;/code&gt;, so the component lands after the app, a full viewport below the layout. The app is also still on the page, so &lt;code&gt;screen&lt;/code&gt; matches its elements as well as the ones your test just rendered. Both of those are the same problem: the app is in the way.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const HOST_ID = &quot;twd-component-host&quot;;
const APP_ROOT_ID = &quot;root&quot;;

let appRoot: HTMLElement | null = null;
let placeholder: Comment | null = null;

export function componentHost(): HTMLElement {
  detachApp();

  let host = document.getElementById(HOST_ID);
  if (!host) {
    host = document.createElement(&quot;div&quot;);
    host.id = HOST_ID;
  }
  if (!host.isConnected) {
    document.body.prepend(host);
  }

  host.innerHTML = &quot;&quot;;
  return host;
}

export function restorePage(): void {
  document.getElementById(HOST_ID)?.remove();
  attachApp();
}

function detachApp(): void {
  if (placeholder) return;

  const root = document.getElementById(APP_ROOT_ID);
  if (!root) return;

  appRoot = root;
  placeholder = document.createComment(&quot; app detached by twd component test &quot;);
  root.replaceWith(placeholder);
}

function attachApp(): void {
  if (!placeholder || !appRoot) return;

  placeholder.replaceWith(appRoot);
  placeholder = null;
  appRoot = null;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Detaching the app root is not the same as emptying it. &lt;code&gt;root.innerHTML = &quot;&quot;&lt;/code&gt; pulls the DOM out from under React while it still holds references to those nodes, and the app does not come back. Moving the node out and putting it back leaves the references intact, so &lt;code&gt;restorePage()&lt;/code&gt; returns a live app.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;prepend&lt;/code&gt; rather than &lt;code&gt;append&lt;/code&gt; puts the component at the top of the page instead of below where the app used to be, so you can watch it run without scrolling.&lt;/p&gt;
&lt;p&gt;The payoff is that &lt;code&gt;screen&lt;/code&gt; behaves exactly like it does in jsdom. The only thing in the document is what your test rendered, which also covers anything the component renders through a portal, since that lands on &lt;code&gt;document.body&lt;/code&gt; rather than inside the container.&lt;/p&gt;
&lt;p&gt;One detail worth keeping: &lt;code&gt;cleanup()&lt;/code&gt; and &lt;code&gt;restorePage()&lt;/code&gt; belong in &lt;code&gt;afterEach&lt;/code&gt;, not &lt;code&gt;beforeEach&lt;/code&gt;. In jsdom the environment is torn down for you between files. In a real browser it is not, so renders stack up, and your flow tests need the app back before they run.&lt;/p&gt;
&lt;p&gt;That is the whole setup. Your app does not change.&lt;/p&gt;
&lt;h3 id=&quot;two-traps&quot;&gt;Two traps&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;screenDom&lt;/code&gt; will not find your component.&lt;/strong&gt; TWD exposes &lt;code&gt;screenDom&lt;/code&gt;, a wrapper around Testing Library queries scoped to your app root so it never matches the TWD sidebar. Testing Library's &lt;code&gt;render()&lt;/code&gt; mounts outside that root. I probed it in a real app to be sure:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;container.parentElement=&amp;lt;body&amp;gt;   inside #root=false
screen: found   screenDom: not found   screenDomGlobal: found
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So use Testing Library's own &lt;code&gt;screen&lt;/code&gt;, or TWD's &lt;code&gt;screenDomGlobal&lt;/code&gt;, which queries the whole document. If you pick &lt;code&gt;screenDomGlobal&lt;/code&gt;, keep queries specific, because it can also match elements inside the sidebar.&lt;/p&gt;
&lt;p&gt;Everything else works normally. &lt;code&gt;twd.should&lt;/code&gt; takes any element you hand it, whether a query found it in your app or in a component you just rendered.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Your test pattern probably says &lt;code&gt;.ts&lt;/code&gt;.&lt;/strong&gt; Component tests are &lt;code&gt;.tsx&lt;/code&gt;. A pattern of &lt;code&gt;/**/*.twd.test.ts&lt;/code&gt; skips them silently, with no error and no missing-file warning. They simply never appear in the sidebar:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;twd({
  testFilePattern: &quot;/**/*.twd.test.{ts,tsx}&quot;,
}),
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you also run Vitest in the same repo, exclude the browser tests from it. Vitest matches &lt;code&gt;*.test.tsx&lt;/code&gt; by default, collects the TWD files, finds no &lt;code&gt;describe&lt;/code&gt; it recognises, and fails the run with &lt;code&gt;No test suite found in file&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;test: {
  exclude: [...configDefaults.exclude, &quot;**/*.twd.test.*&quot;],
},
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;both-kinds-of-test-one-run&quot;&gt;Both kinds of test, one run&lt;/h3&gt;
&lt;p&gt;This is the part I did not expect to matter as much as it does.&lt;/p&gt;
&lt;p&gt;Component tests and flow tests are now the same kind of artifact. They are files in the same project, running in the same browser, in the same session, against the same instrumented bundle. So one command runs both:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-console&quot;&gt;$ npx twd-cli run
Running 14 test(s)...
Code coverage data written to .nyc_output/out.json

--- Run complete ---
  Passed: 14 | Failed: 0 | Skipped: 0
  Duration: 6.9s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ten of those drive the whole app through routing, search, sorting and deletion. Four render a single dialog component in isolation. One coverage file comes out the other end, covering both.&lt;/p&gt;
&lt;p&gt;That last part is usually where multi-runner setups get tedious. Component coverage in one report, end-to-end coverage in another, and a merge step that someone maintains. Here there is nothing to merge, because there was only ever one run.&lt;/p&gt;
&lt;h3 id=&quot;where-each-style-fits&quot;&gt;Where each style fits&lt;/h3&gt;
&lt;p&gt;Rendering a component in isolation is the right move when the component is the subject: a form's validation states, a dialog that opens and closes, a table that sorts. You skip the navigation, you skip the fixtures, and the test says exactly what it is about.&lt;/p&gt;
&lt;p&gt;Flow tests stay the right move for anything that crosses a boundary. Routing, data loading, a sequence of screens, state that survives a navigation. Rendering a component in isolation to test those means rebuilding the app around it, which is how component test files end up longer than the components.&lt;/p&gt;
&lt;p&gt;The useful change is not that one replaced the other. It is that choosing between them is now a decision about scope, made per test, instead of a decision about which runner and which DOM you are committing to.&lt;/p&gt;
&lt;h3 id=&quot;try-it&quot;&gt;Try it&lt;/h3&gt;
&lt;p&gt;If you already have Testing Library tests, the fastest way to see this is to copy one, change the imports for &lt;code&gt;describe&lt;/code&gt; and &lt;code&gt;it&lt;/code&gt; to &lt;code&gt;twd-js/runner&lt;/code&gt;, and hand &lt;code&gt;render()&lt;/code&gt; the component host.&lt;/p&gt;
&lt;p&gt;The example app from this post is on GitHub, with the same component tested in jsdom and in the browser side by side: &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/kevinccbsg/frontend-challenge&quot;&gt;kevinccbsg/frontend-challenge&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the next post I look at what happened when I put those two versions next to each other. The jsdom test mocked the hook it was testing through, and once I stopped mocking, it turned out the mocks had been doing most of the work.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/25909/no-more-fake-dom-testing-library-unit-tests-in-the-real-browser</guid>
<pubDate>Mon, 31 Aug 2026 07:54:58 +0000</pubDate>
</item>
<item>
<title>Architectural Elegance in Frontend Testing: Mastering the Builder Pattern and Test Directory Layouts</title>
<link>https://coderlegion.com/20285/architectural-elegance-frontend-testing-mastering-builder-pattern-directory-layouts</link>
<description>&lt;p&gt;As frontend applications scale, their architectures mature. We regularly decouple our systems into clean state management layers, dedicated service modules, and isolated data repositories. However, while our production code advances, our testing suites frequently lag behind.&lt;/p&gt;
&lt;p&gt;Two critical pain points eventually stall any scaling frontend test suite, whether built on &lt;strong&gt;Vue 3&lt;/strong&gt; or &lt;strong&gt;React&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;The Static Mock Graveyard:&lt;/strong&gt; Uncontrolled, brittle data mocking that breaks with every contract change.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Directory Sprawl:&lt;/strong&gt; The endless debate of where to place test files, leading to a messy, unmaintainable codebase.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This article tackles both challenges by introducing the &lt;strong&gt;Test Data Builder Pattern&lt;/strong&gt; and establishing a &lt;strong&gt;&quot;Goldilocks&quot; Hybrid Directory Layout&lt;/strong&gt; designed for modern frontend environments.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;1-the-problem-why-traditional-mocking-scales-horribly&quot;&gt;1. The Problem: Why Traditional Mocking Scales Horribly&lt;/h3&gt;
&lt;p&gt;When testing components or services that rely on complex, contract-backed data types, developers usually fall into two traps:&lt;/p&gt;
&lt;h4 id=&quot;trap-a-inline-literal-hardcoding&quot;&gt;Trap A: Inline Literal Hardcoding&lt;/h4&gt;
&lt;p&gt;Declaring massive object literals directly inside local &lt;code&gt;describe&lt;/code&gt; or &lt;code&gt;it&lt;/code&gt; blocks.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// tests/components/UserCard.spec.ts
it('renders user details', () =&amp;gt; {
  const mockUser = { id: '1', name: 'John', email: '*Emails are not allowed*', role: 'user', status: 'active', permissions: [] /* ... 20 more fields */ };
  const wrapper = mount(UserCard, { props: { user: mockUser } });
});

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Why it fails:&lt;/strong&gt; If your backend schema changes and a new required field is introduced, you must manually hunt down and update thousands of lines of inline configurations across hundreds of test files.&lt;/p&gt;
&lt;h4 id=&quot;trap-b-the-centralized-mock-folder-of-doom-&quot;&gt;Trap B: The &quot;Centralized Mock Folder of Doom&quot;&lt;/h4&gt;
&lt;p&gt;Creating a root-level static folder (e.g., &lt;code&gt;/fixtures&lt;/code&gt;) packed with frozen JSON payloads like &lt;code&gt;user.json&lt;/code&gt;, &lt;code&gt;adminUser.json&lt;/code&gt;, and &lt;code&gt;bannedAdminUser.json&lt;/code&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The Mutation Nightmare:&lt;/strong&gt; If &lt;code&gt;Test A&lt;/code&gt; imports a shared mock file and accidentally mutates a nested property inline, &lt;code&gt;Test B&lt;/code&gt; (running concurrently) will suddenly fail with a mysterious state bug.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Naming Explosion:&lt;/strong&gt; Your folder quickly becomes a graveyard of &lt;code&gt;user1.json&lt;/code&gt;, &lt;code&gt;user2.json&lt;/code&gt;, and &lt;code&gt;updatedUserFinal.json&lt;/code&gt; as tests demand slight data variations.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;2-the-solution-the-test-data-builder-pattern&quot;&gt;2. The Solution: The Test Data Builder Pattern&lt;/h3&gt;
&lt;p&gt;The &lt;strong&gt;Builder Pattern&lt;/strong&gt; replaces rigid static files with a dynamic, fluid assembly line. Instead of maintaining discrete states across countless individual files, you configure a single class that maintains sensible, contract-satisfying defaults. It exposes chainable methods to alter just the pieces of data a specific test cares about.&lt;/p&gt;
&lt;p&gt;By having configuration methods &lt;code&gt;return this&lt;/code&gt;, your test code reads like an expressive sentence. Crucially, the termination method (&lt;code&gt;.build()&lt;/code&gt;) returns a completely fresh, deeply unlinked clone of the payload, preventing cross-test state contamination.&lt;/p&gt;
&lt;h4 id=&quot;the-typescript-implementation&quot;&gt;The TypeScript Implementation&lt;/h4&gt;
&lt;p&gt;Imagine an entity generated from a backend database contract:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// src/types/user.ts
export interface UserProfile {
  id: string;
  username: string;
  email: string;
  role: 'admin' | 'subscriber' | 'guest';
  status: 'active' | 'suspended';
  permissions: string[];
}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Instead of copying raw objects, create a reusable &lt;code&gt;UserProfileBuilder&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// tests/builders/UserProfileBuilder.ts
import type { UserProfile } from '@/types/user';

export class UserProfileBuilder {
  // 1. Sensible default values that satisfy the TS contract
  private data: UserProfile = {
    id: 'usr_default_101',
    username: 'test_user',
    email: '*Emails are not allowed*',
    role: 'subscriber',
    status: 'active',
    permissions: ['view:dashboard']
  };

  // 2. Chainable semantic modifiers
  asAdmin(): this {
    this.data.role = 'admin';
    this.data.permissions = ['view:dashboard', 'write:settings', 'delete:users'];
    return this; // Crucial for method chaining
  }

  asSuspended(): this {
    this.data.status = 'suspended';
    return this;
  }

  withCustomUsername(name: string): this {
    this.data.username = name;
    return this;
  }

  // 3. Finalization mechanism providing deep safety guarantees
  build(): UserProfile {
    // Return a deep clone to guarantee total test isolation
    return JSON.parse(JSON.stringify(this.data));
  }
}

&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;3-integrating-builders-into-component-testing&quot;&gt;3. Integrating Builders into Component Testing&lt;/h3&gt;
&lt;p&gt;Look at how expressive and readable your unit and integration specs become. You don't have to wade through lines of irrelevant object properties; the code tells you exactly what state is being evaluated.&lt;/p&gt;
&lt;h4 id=&quot;in-vue-3-vitest-vue-test-utils-&quot;&gt;In Vue 3 (Vitest + Vue Test Utils)&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;import { describe, it, expect } from 'vitest';
import { mount } from '@vue/test-utils';
import UserCard from '@/components/UserCard.vue';
import { UserProfileBuilder } from 'tests/builders/UserProfileBuilder';

describe('UserCard.vue', () =&amp;gt; {
  it('hides delete action for standard subscribers', () =&amp;gt; {
    const standardUser = new UserProfileBuilder().build(); // Fresh default user
    const wrapper = mount(UserCard, { props: { user: standardUser } });
    
    expect(wrapper.find('.btn-delete').exists()).toBe(false);
  });

  it('reveals danger actions for admin users', () =&amp;gt; {
    const adminUser = new UserProfileBuilder().asAdmin().build(); // Instant admin state
    const wrapper = mount(UserCard, { props: { user: adminUser } });
    
    expect(wrapper.find('.btn-delete').exists()).toBe(true);
  });
});

&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;in-react-vitest-react-testing-library-&quot;&gt;In React (Vitest + React Testing Library)&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;import { describe, it, expect } from 'vitest';
import { render, screen } from '@testing-library/react';
import UserCard from '@/components/UserCard';
import { UserProfileBuilder } from 'tests/builders/UserProfileBuilder';

describe('UserCard Component', () =&amp;gt; {
  it('hides delete action for standard subscribers', () =&amp;gt; {
    const standardUser = new UserProfileBuilder().build();
    render(&amp;lt;UserCard user={standardUser} /&amp;gt;);
    
    expect(screen.queryByRole('button', { name: /delete/i })).not.toBeInTheDocument();
  });

  it('reveals danger actions for admin users', () =&amp;gt; {
    const adminUser = new UserProfileBuilder().asAdmin().withCustomUsername('Boss').build();
    render(&amp;lt;UserCard user={adminUser} /&amp;gt;);
    
    expect(screen.getByText('Boss')).toBeInTheDocument();
    expect(screen.getByRole('button', { name: /delete/i })).toBeInTheDocument();
  });
});

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The Maintenance Win:&lt;/strong&gt; If your API shifts tomorrow and a user profile now requires a &lt;code&gt;phoneNumber&lt;/code&gt; field, you add it &lt;strong&gt;once&lt;/strong&gt; to the defaults inside &lt;code&gt;UserProfileBuilder&lt;/code&gt;. None of your component tests will break.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;4-resolving-the-tests-directory-layout-conflict&quot;&gt;4. Resolving the &lt;code&gt;__tests__&lt;/code&gt; Directory Layout Conflict&lt;/h3&gt;
&lt;p&gt;Where do you actually put these test files? Frontend teams often flip-flop between two extreme layouts, both of which degrade at scale:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The Problem with Pure Collocation (&lt;code&gt;__tests__&lt;/code&gt; Bloat):&lt;/strong&gt; Grouping tests inside isolated &lt;code&gt;__tests__&lt;/code&gt; folders under every single feature sub-layer introduces massive visual noise. It clutters your tree, making standard file navigation frustrating.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Problem with Pure Centralization:&lt;/strong&gt; Moving &lt;em&gt;every&lt;/em&gt; single test outside the &lt;code&gt;src/&lt;/code&gt; directory into a massive top-level &lt;code&gt;/tests&lt;/code&gt; folder detaches specs from code lifetimes. When you delete or refactor a component, finding and maintaining its parallel test target across the repository introduces heavy cognitive overhead.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;the-goldilocks-hybrid-strategy&quot;&gt;The &quot;Goldilocks&quot; Hybrid Strategy&lt;/h4&gt;
&lt;p&gt;The ideal layout divides your testing ecosystem based on the &lt;strong&gt;operational scope&lt;/strong&gt; of the test.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Collocate Implementation Tests (No &lt;code&gt;__tests__&lt;/code&gt; Folders):&lt;/strong&gt; Put unit and integration tests (&lt;code&gt;.spec.ts&lt;/code&gt;) &lt;strong&gt;directly next&lt;/strong&gt; to their matching components or domain modules. If you move or delete a feature, its test naturally follows it. Ditch the nested &lt;code&gt;__tests__&lt;/code&gt; directory to minimize visual noise.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Centralize Test Infrastructure Machinery:&lt;/strong&gt; Global assets like your custom &lt;strong&gt;Test Data Builders&lt;/strong&gt;, Mock Service Worker (MSW) interceptors, and framework setup scripts are shared resources. They belong in a centralized root-level &lt;code&gt;/tests&lt;/code&gt; chamber.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Isolate End-to-End Specs:&lt;/strong&gt; Black-box test frameworks (Playwright, Cypress) treat your application as an independent environment. They live completely outside of &lt;code&gt;src/&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;the-production-blueprint-file-tree&quot;&gt;The Production Blueprint File Tree&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;my-application/
├── e2e/                     # Centralized End-to-End suite
│   └── auth-flow.spec.ts
├── src/
│   ├── components/          # UI Components with collocated tests
│   │   ├── CustomButton.vue
│   │   ├── CustomButton.spec.ts
│   │   ├── UserProfileCard.vue
│   │   └── UserProfileCard.spec.ts
│   ├── domains/             # Domain-driven backend abstractions
│   │   └── user/
│   │       ├── UserRepository.ts
│   │       ├── UserRepository.spec.ts  # Clean, close proximity
│   │       └── UserService.ts
├── tests/                   # Shared Test Infrastructure Hub
│   ├── vitest.setup.ts      # Framework bootstrap configuration
│   ├── builders/            # The Central Builder Room
│   │   ├── UserProfileBuilder.ts
│   │   └── ProductPayloadBuilder.ts
│   └── msw/                 # Global Network Mock Handlers
│       ├── browser.ts
│       └── handlers.ts
└── vitest.config.ts

&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;summary-designing-for-the-future&quot;&gt;Summary: Designing for the Future&lt;/h3&gt;
&lt;p&gt;By organizing your testing framework with this approach, you enforce two strict architectural principles:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Decouple Data Arrangement from Assertions:&lt;/strong&gt; Leave your component tests to focus purely on mounting, user interaction, and output evaluation. Delegate the complex assembly of mock states to structured Builders.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Match Proximity to File Lifetime:&lt;/strong&gt; If a test verifies a singular implementation file (a specific component, service, or composable hook), keep them side-by-side. If a file exists purely to support &lt;em&gt;other&lt;/em&gt; tests across your application (like global builders), lift it to the centralized infrastructure hub.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Adopting these practices shifts your frontend testing environment from a fragile maintenance bottleneck into a scalable, developer-friendly validation system.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/20285/architectural-elegance-frontend-testing-mastering-builder-pattern-directory-layouts</guid>
<pubDate>Thu, 11 Jun 2026 11:01:04 +0000</pubDate>
</item>
<item>
<title>Exploring Testing Strategies for Node.js Projects</title>
<link>https://coderlegion.com/12215/exploring-testing-strategies-for-node-js-projects</link>
<description>&lt;p&gt;Testing is often overlooked in rapid development cycles, but it's crucial for delivering robust applications. In Node.js, effective testing can be achieved through various strategies:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Unit Testing with Mocha and Chai&lt;/strong&gt;: Mocha provides a flexible testing framework, while Chai offers an expressive assertion library. For example, you can test a function like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;const assert = require('chai').assert;
const app = require('../app');
   
describe('App', function() {
  it('should return hello world', function() {
    assert.equal(app(), 'hello world');
  });
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Running your tests with Mocha ensures early bug detection.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Integration Testing with Supertest&lt;/strong&gt;: Supertest can help test your RESTful APIs effectively. It allows you to simulate HTTP requests and validate responses. For instance:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;const request = require('supertest');
const app = require('../app');
   
describe('GET /api/users', function() {
  it('responds with json', function(done) {
    request(app)
      .get('/api/users')
      .expect('Content-Type', /json/)  
      .expect(200, done);
  });
});
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;End-to-End Testing with Cypress&lt;/strong&gt;: For comprehensive application testing, Cypress allows you to write end-to-end tests in a user-centric way. You can simulate real user interactions and validate features.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;describe('My First Test', function() {
  it('Visits the Kitchen Sink', function() {
    cy.visit('https://example.cypress.io');
    cy.contains('type').click();
    cy.url().should('include', '/commands/actions');
  });
});
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Continuous Integration with GitHub Actions&lt;/strong&gt;: Implementing CI/CD pipelines ensures that your tests run automatically upon code commits. You can define a &lt;code&gt;.github/workflows/node.js.yml&lt;/code&gt; that runs tests on various Node.js versions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Code Coverage with Istanbul&lt;/strong&gt;: Ensure your tests cover critical parts of your codebase by using Istanbul. It helps visualize untested parts and enables you to focus your testing efforts effectively.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In conclusion, by embracing these testing strategies, you not only improve your application's quality but also enhance team collaboration and project sustainability. Start integrating these methods into your Node.js projects today!&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/12215/exploring-testing-strategies-for-node-js-projects</guid>
<pubDate>Thu, 26 Feb 2026 18:42:27 +0000</pubDate>
</item>
<item>
<title>The Hidden Power of Your Test Setup and Mocks</title>
<link>https://coderlegion.com/5054/the-hidden-power-of-your-test-setup-and-mocks</link>
<description>&lt;p&gt;Have you ever looked at a test file and seen the same setup code repeated over and over? Maybe you're mocking the same API service, or setting up a global &lt;code&gt;localStorage&lt;/code&gt; mock in dozens of different files. This isn't just a nuisance; it's a huge problem. This leads to &lt;strong&gt;duplication&lt;/strong&gt; and &lt;strong&gt;tight coupling&lt;/strong&gt;, making your tests difficult to maintain.&lt;/p&gt;
&lt;p&gt;We need a way to &lt;strong&gt;decouple our tests from our dependencies&lt;/strong&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;centralizing-with-vitest-setup-ts&quot;&gt;Centralizing with &lt;code&gt;vitest.setup.ts&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;vitest.setup.ts&lt;/code&gt; or &lt;code&gt;jest.setup.ts&lt;/code&gt; file is a central place for code that should run &lt;strong&gt;before every test file&lt;/strong&gt;. Its main advantage is that it allows you to configure global test settings and, most importantly, &lt;strong&gt;set up global mocks&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Imagine you have an API service for user authentication that's used across your application. Instead of mocking it in every test file, you can do it once in your setup file.&lt;/p&gt;
&lt;p&gt;Here's a simple &lt;code&gt;vitest.setup.ts&lt;/code&gt; example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// vitest.setup.ts

import { vi } from &quot;vitest&quot;;
import * as authService from &quot;@/services/authService&quot;;

// We export the mocked functions so we can access and override them
export const isUserLoggedIn = vi.spyOn(authService, &quot;isLoggedIn&quot;).mockReturnValue(true);
export const getCurrentLoggedInUser = vi
  .spyOn(authService, &quot;getCurrentUser&quot;)
  .mockReturnValue({ id: 1, name: &quot;Test User&quot; });
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, every single test you run will automatically use this mock for &lt;code&gt;authService&lt;/code&gt;. You no longer need to write &lt;code&gt;vi.mock()&lt;/code&gt; at the top of every file. This saves time, reduces duplication, and makes your tests much cleaner.&lt;/p&gt;
&lt;p&gt;The primary benefit is &lt;strong&gt;maintainability&lt;/strong&gt;. If you need to update the &lt;code&gt;authService&lt;/code&gt; mock, you only have to change it in one place.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;flexibility-overriding-mocks-in-specific-tests&quot;&gt;Flexibility: Overriding Mocks in Specific Tests&lt;/h3&gt;
&lt;p&gt;This is where the real power comes in. While you have a global default mock, sometimes you need a specific test to behave differently. By exporting the mocked functions from your setup file, you can easily override their return values for a particular test case.&lt;/p&gt;
&lt;p&gt;Let's say you have a component that should show a different message if the user is not logged in. You can write a test for this specific scenario like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// SomeComponent.test.ts

import { mount } from &quot;@vue/test-utils&quot;;
import SomeComponent from &quot;@/components/SomeComponent.vue&quot;;
import { isUserLoggedIn } from &quot;../../vitest.setup.ts&quot;; // Import the mocked function

describe(&quot;SomeComponent&quot;, () =&amp;gt; {
  it(&quot;should show a login message if the user is not logged in&quot;, async () =&amp;gt; {
    // Override the globally mocked function for this specific test
    isUserLoggedIn.mockReturnValueOnce(false);

    const wrapper = mount(SomeComponent);
    expect(wrapper.text()).toContain(&quot;Please log in to continue.&quot;);
  });

  // Other tests will still use the default mock of `isUserLoggedIn` returning true.
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This approach combines the best of both worlds: a &lt;strong&gt;global default&lt;/strong&gt; mock for most tests, but the flexibility to &lt;strong&gt;customize&lt;/strong&gt; the mock's behavior for tests that require a different scenario. This is a crucial aspect of writing robust and comprehensive tests.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;advanced-mocking-partial-mocks-and-hoisting&quot;&gt;Advanced Mocking: Partial Mocks and Hoisting&lt;/h3&gt;
&lt;p&gt;Sometimes you don't want to mock an entire module; you just want to replace one or two functions while keeping the rest of the original implementation. This is where more advanced mocking techniques come into play.&lt;/p&gt;
&lt;h4 id=&quot;mocking-with-vi-hoisted&quot;&gt;Mocking with &lt;code&gt;vi.hoisted&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;Normally, you can't access variables from your test file inside a &lt;code&gt;vi.mock&lt;/code&gt; factory. &lt;strong&gt;&lt;code&gt;vi.hoisted&lt;/code&gt;&lt;/strong&gt; solves this by &quot;hoisting&quot; the mock definition to the top of the file, allowing you to create dynamic mocks. This is useful when your mock's behavior depends on a variable you define in your test.&lt;/p&gt;
&lt;p&gt;You can also use &lt;code&gt;vi.hoisted&lt;/code&gt; to create a reusable mock function that can be used inside multiple &lt;code&gt;vi.mock&lt;/code&gt; calls, making your mock logic cleaner and more consistent.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// SomeComponent.test.ts

import { vi } from &quot;vitest&quot;;

const mockedGetPosts = vi.hoisted(() =&amp;gt; {
  return vi.fn(() =&amp;gt;
    Promise.resolve([
      { id: 1, title: &quot;Mock Post 1&quot; },
      { id: 2, title: &quot;Mock Post 2&quot; },
    ]),
  );
});

vi.mock(&quot;@/api&quot;, () =&amp;gt; ({
  getPosts: mockedGetPosts, // Reusing the hoisted mock function
}));

describe(&quot;SomeComponent&quot;, () =&amp;gt; {
  it(&quot;should fetch and display posts on mount&quot;, async () =&amp;gt; {
    // The `getPosts` function is already the mocked version
    const wrapper = shallowMount(SomeComponent);
    await wrapper.vm.$nextTick();
    expect(mockedGetPosts).toHaveBeenCalled();
  });
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a more complex but very powerful way to create flexible mocks.&lt;/p&gt;
&lt;h4 id=&quot;partial-mocks-with-vi-importactual&quot;&gt;Partial Mocks with &lt;code&gt;vi.importActual&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;For more fine-grained control, you can use &lt;strong&gt;&lt;code&gt;vi.importActual&lt;/code&gt;&lt;/strong&gt; (or &lt;strong&gt;&lt;code&gt;vi.importOriginal&lt;/code&gt;&lt;/strong&gt; for CommonJS modules) inside a mock factory. This function gives you access to the real, un-mocked module, allowing you to only mock the parts you need.&lt;/p&gt;
&lt;p&gt;Let's say you only want to mock the &lt;code&gt;isLoggedIn&lt;/code&gt; function but keep the original &lt;code&gt;getCurrentUser&lt;/code&gt; function.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// authService.test.ts

import { vi } from &quot;vitest&quot;;

vi.mock(&quot;@/services/authService&quot;, async (importActual) =&amp;gt; {
  const actualAuth = await importActual&amp;lt;typeof import(&quot;@/services/authService&quot;)&amp;gt;();
  return {
    ...actualAuth, // Use all original exports
    isLoggedIn: vi.fn(() =&amp;gt; true), // But override this one
  };
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This ensures that your test only overrides the specific behavior it needs to, further reducing the coupling between your test and the implementation details of the module.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-magic-of-the-mocks-directory&quot;&gt;The Magic of the &lt;code&gt;__mocks__&lt;/code&gt; Directory&lt;/h3&gt;
&lt;p&gt;While &lt;code&gt;vitest.setup.ts&lt;/code&gt; is great for global mocks, the &lt;code&gt;__mocks__&lt;/code&gt; directory is the perfect solution for &lt;strong&gt;automatic mocking of modules&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;When you place a file with the same name as a module inside a &lt;code&gt;__mocks__&lt;/code&gt; directory, Vitest (and Jest) will automatically use that file as the mock whenever the original module is imported. You can even use &lt;code&gt;vi.importActual&lt;/code&gt; within this mock file to create partial mocks automatically.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;__mocks__&lt;/code&gt; directory provides &lt;strong&gt;loose coupling&lt;/strong&gt; between your tests and your implementation. Your test file has no idea that &lt;code&gt;fetchPosts&lt;/code&gt; is being mocked; it simply imports it and uses it. This makes your tests more robust and less likely to break when you refactor your original code.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-ultimate-payoff-decoupled-and-resilient-tests&quot;&gt;The Ultimate Payoff: Decoupled and Resilient Tests&lt;/h3&gt;
&lt;p&gt;The real power of these tools is that they allow you to create tests that only care about the &lt;strong&gt;behavior&lt;/strong&gt; of your code, not its internal dependencies.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;vitest.setup.ts&lt;/code&gt;&lt;/strong&gt; is for &lt;strong&gt;global, application-wide mocks&lt;/strong&gt; that apply to all your tests. You can also export these mocks for overriding.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;__mocks__&lt;/code&gt;&lt;/strong&gt; is for &lt;strong&gt;automatic, module-level mocks&lt;/strong&gt; that apply whenever a specific module is imported.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;vi.hoisted&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;code&gt;vi.importActual&lt;/code&gt;&lt;/strong&gt; provide the necessary flexibility for creating advanced, partial mocks when simple mocking isn't enough.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By using these tools, you're not just making your tests shorter. You're building a testing strategy that's resilient to change. You can refactor your services, change your API endpoints, or switch data libraries, and your tests will remain intact, as long as the mocked behavior is consistent.&lt;/p&gt;
</description>
<category>Unit Testing</category>
<guid isPermaLink="true">https://coderlegion.com/5054/the-hidden-power-of-your-test-setup-and-mocks</guid>
<pubDate>Wed, 27 Aug 2025 11:55:39 +0000</pubDate>
</item>
<item>
<title>How I Started Writing Unit Tests for Vue Components</title>
<link>https://coderlegion.com/1682/how-i-started-writing-unit-tests-for-vue-components</link>
<description>&lt;p&gt;At some point, every frontend developer realizes that it would be great to somehow verify that their code is working as expected. For me, this moment came after a painful migration from Vue 2 to Vue 3, with tons of bugs and defects. It left me with yet another strand of gray hair, and I wasn’t the only one suffering.&lt;/p&gt;
&lt;h3 id=&quot;my-project-and-technology-stack&quot;&gt;My project and technology stack&lt;/h3&gt;
&lt;p&gt;The current project I’m working on is a classic CRM, full of forms upon forms, list rendering, modals, and constant data transformation. The technology stack includes Vue 3, Pinia, Vite, and ElementPlus, which allows for fast and flexible interface development. &lt;/p&gt;
&lt;h3 id=&quot;why-unit-tests-&quot;&gt;Why unit tests?&lt;/h3&gt;
&lt;p&gt;After reading up on the theory behind pyramids and testing cups, I concluded that it’s easier to gradually add “unit” tests for new components and features, as well as cover any bugs with tests.&lt;/p&gt;
&lt;p&gt;Just a quick note on the testing pyramid. This concept, introduced by Martin Fowler, helps organize tests in a project. It involves three levels of testing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Unit Tests&lt;/strong&gt;: the most basic level of testing, which checks individual modules or functions. Unit tests are fast, easy to set up&lt;br&gt;
and ensure that components work correctly in isolation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Integration Tests&lt;/strong&gt;: test the interaction between multiple components or modules, like how components work together on a page.&lt;br&gt;
They are more complex and slower, but provide an understanding of the&lt;br&gt;
correctness of the integrations.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;E2E tests (End-to-End Tests)&lt;/strong&gt;: test the entire application, simulating real user actions. E2E tests are slower and require&lt;br&gt;
complex infrastructure but ensure that the app works as a whole.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The word &quot;unit&quot; is in quotes here because, when testing components in a framework, there’s a nuance: testing components isn’t always about isolating them completely. &lt;/p&gt;
&lt;p&gt;Ideally, unit tests check isolated functions, (like the famous SUM () function), but in reality, we cannot entirely &quot;mock&quot; the framework. So, tests for Vue components are technically integration tests. However, for simplicity, the community continues to call them “unit tests” and I’ll stick with that terminology. &lt;/p&gt;
&lt;h3 id=&quot;testing-options-and-my-choice&quot;&gt;Testing options and my choice&lt;/h3&gt;
&lt;p&gt;Of course, there were other options. For example, I considered E2E testing with Playwright, which runs tests in real browsers simulating user actions. While Playwright is a powerful tool,I faced several infrastructure difficulties, which I’ll discuss later in the article.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Spoiler: the backend wasn't ready for this, and realistically, E2E tests should be written under the guidance of QA engineers - they are experts at breaking systems.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Ultimately, I decided to go with Vitest and Vue Test Utils as the main tools for testing. Vitest, as a test runner, was ideal, since Vite was already installed in the project, and Vue Test Utils provided all the necessary tools for mounting and modifying Vue components.&lt;/p&gt;
&lt;p&gt;Why Vue Test Utils and not Testing Library? First, Vue Text Urils is recommended by the Vue community (Testing Library was a bit late in supporting Vue 3). Second, I follow &quot;London School&quot; of testing, where we mock everything around our component to keep tests as fair isolated as possible. In addition, the Testing Library is built on top of VTU, and I wanted fewer dependencies.&lt;/p&gt;
&lt;h3 id=&quot;installing-and-setting-up&quot;&gt;Installing and setting up&lt;/h3&gt;
&lt;p&gt;To get started, we need to install and configure &lt;a rel=&quot;nofollow&quot; href=&quot;https://vitest.dev/guide/&quot;&gt;Vitest&lt;/a&gt; and &lt;a rel=&quot;nofollow&quot; href=&quot;https://test-utils.vuejs.org/installation/&quot;&gt;Vue test utils&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm i -D vitest @vue/test-utils
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since our tests will run in a Node.js environment, we need DOM implementers. Vitest recommends either happy-dom or jsdom. &lt;/p&gt;
&lt;p&gt;I chose jsdom because it’s more popular and faster, though happy-dom is an option as well as you can switch quickly.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm i jsdom -D
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;configuring-the-testing-environment&quot;&gt;Configuring the testing environment&lt;/h3&gt;
&lt;p&gt;Let's add the necessary configuration to vite.config.js.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;defineConfig({
...
test: {
environment: 'jsdom',
deps: {
  inline: ['element-plus'], // optional field
},
},
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since Pinia is in the stack, we can either use a real store or a &lt;a rel=&quot;nofollow&quot; href=&quot;https://pinia.vuejs.org/cookbook/testing.html&quot;&gt;test store for testing&lt;/a&gt;. I opted for a test store, as it’s easier to mutate directly during tests.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm i -D @pinia/testing
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;what-and-how-to-test-&quot;&gt;What and how to test?&lt;/h3&gt;
&lt;p&gt;Let's take a component with a button and a modal as an example.&lt;/p&gt;
&lt;p&gt;Component diagram and description &lt;/p&gt;
&lt;p&gt;Here’s the basic flow:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;There is a button (which is enabled if the user has permission).&lt;/li&gt;
&lt;li&gt;When clicked, it opens a form in a modal window (a separate&lt;br&gt;
component).&lt;/li&gt;
&lt;li&gt;When the form is filled and the &quot;Add&quot; button is clicked, a request is&lt;br&gt;
sent to the server.&lt;/li&gt;
&lt;li&gt;After a successful response, an event is emitted to indicate that the&lt;br&gt;
document has been added.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=10403058242445935004&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Component code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;template&amp;gt;
 &amp;lt;div&amp;gt;
   &amp;lt;button :disabled=&quot;!isAddDocumentAvailable&quot; class=&quot;button button--primary&quot; @click=&quot;addIncomingMail&quot;&amp;gt;Add incoming correspondence&amp;lt;/button&amp;gt;
   &amp;lt;popup drawer :is-form-open=&quot;isFormOpen&quot; @closed=&quot;closeForm&quot;&amp;gt;
     &amp;lt;add-incoming-mail-modal :lawsuit-id=&quot;lawsuitId&quot; @closeForm=&quot;closeForm&quot; @mail-added=&quot;onMailChanged&quot; &amp;gt;
   &amp;lt;/popup&amp;gt;
 &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup &amp;gt;
import { ref } from 'vue';
import AddIncomingMailModal from '@/.../AddIncomingMailModal.vue';
const isFormOpen = ref(false);

const emits = defineEmits(['mail-added']);
defineProps({
 lawsuitId: {
   type: Number,
   required: true,
 },
});

function addIncomingMail() {
 isFormOpen.value = true;
}

function closeForm() {
 isFormOpen.value = false;
}
function onMailChanged() {
 emits('mail-added');
}
const isAddDocumentAvailable = computed(() =&amp;gt; {
 return checkAvailabilityByClaim(...);
});
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A bit of theory. &lt;/p&gt;
&lt;p&gt;To start, we need to decide what should be tested. The general advice is to follow the user's behavior and avoid focusing on implementation details, which makes sense. Essentially, we’ll treat the component as a black box: changing (preparing) its input data and testing the output.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Note: if the component has a complex function with heavy calculations, it should ideally be extracted and tested separately as a traditional unit test.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Mocks and stubs play a key role in isolating tests. Mocks replace real dependencies, while stubs simplify interaction with external systems (API, for example). The main rule is not to mock everything: only mock what affects the functionality being tested. This reduces test dependence on the mock.&lt;/p&gt;
&lt;p&gt;Input data includes properties, components, dependency injections, external stores, and slots. For a fair test, we should replace real components, stores, and DIs with stubs. This minimizes the risk of false positives.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=1106737940856126993&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Output: we should test the resulting HTMLcheck  API calls (which should also be stubbed to avoid affecting the backend), and verify that events are emitted and handled correctly outside the component. &lt;/p&gt;
&lt;p&gt;Let's move on to writing the test. First, we need to define what we are testing (as they say, &quot;draw a circle&quot;).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;describe('Adding incoming correspondence - AddIncomingMail', () =&amp;gt; {

 it.todo('The &quot;Add incoming correspondence&quot; button is active if the user has rights', async () =&amp;gt; {});

 it.todo('By clicking on the &quot;Add incoming correspondence&quot; button, a modal window for adding a new document opens', async () =&amp;gt; {});

 it.todo('When adding incoming correspondence, we generate an event outside the component', async () =&amp;gt; {});
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice how these test descriptions serve as self-documenting code — in theory.&lt;/p&gt;
&lt;p&gt;I prefer placing tests as close to the components as possible. This approach seems better suited for understanding how the component works.&lt;/p&gt;
&lt;p&gt;In general, we draw another circle, add details, and - we have a test.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { getButtonByText } from '@/mocks/helpersForTesting/searchElements/index.js';
import { mount } from '@vue/test-utils';
import AddIncomingMail from '@/components/AddIncomingMail.vue';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { createTestingPinia } from '@pinia/testing';

let wrapper; // storing a component instance

beforeEach(() =&amp;gt; { // before each test we mount the component with the initial settings
 wrapper = mount(AddIncomingMail, {
   global: {
plugins:[    
createTestingPinia({ // Create a test instance of Pinia
         createSpy: vi.fn,
         stubActions: false,
         initialState: {
           user: {
             state: {
               claims: [1,2],
             },
           },
         },
       }),]
     stubs: { // Since this is unit testing, we replace all child components with stubs
       AddIncomingMailModal: {
         name: 'AddIncomingMailModal',
         emits: ['mail-added'],
         template: '&amp;lt;div&amp;gt;&amp;lt;h2 &amp;gt;Add correspondence&amp;lt;/h2&amp;gt;&amp;lt;/div&amp;gt;',
       },
       popup: {
         props: { isFormOpen: false },
         template: '&amp;lt;div v-if=&quot;isFormOpen&quot;&amp;gt;&amp;lt;slot&amp;gt;&amp;lt;/div&amp;gt;',
       },
     },
   },
   props: {
     lawsuitId: 15,
   },
 });
});

afterEach(() =&amp;gt; { // After each test, we reset the stubs and destroy the instance
 wrapper.unmount();
 vi.resetAllMocks();
});

describe('Adding incoming correspondence - AddIncomingMail', () =&amp;gt; {
 it('The &quot;Add incoming correspondence&quot; button is active if the user has rights', async () =&amp;gt; {
   const button = getButtonByText({ wrapper, buttonText: 'Add incoming correspondence' }); // Made a helper for quick search of buttons

expect(button.element.disabled).toBe(false);
});

 it('By clicking on the &quot;Add incoming correspondence&quot; button, a modal window for adding a new document opens', async () =&amp;gt; {
   const button = getButtonByText({ wrapper, buttonText: 'Add incoming correspondence' });

   await button.trigger('click');
   await wrapper.vm.$nextTick(); //Since Vue makes changes asynchronously, it is important to wait

   expect(wrapper.text()).contain('Add correspondence');
 });

it('When adding incoming correspondence, we generate an event outside the component', async () =&amp;gt; {
   const button = getButtonByText({ wrapper, buttonText: 'Add incoming correspondence' });
   await button.trigger('click');
   await wrapper.vm.$nextTick();
   const modalStub = wrapper.findComponent({ name: 'AddIncomingMailModal' });

   modalStub.vm.$emit('mail-added');
   expect(wrapper.emitted()).toHaveProperty('mail-added');
 });
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I would like to draw your attention to how element searching occurs. You should try to search for elements the way a user would search. A less recommended, but more popular approach is using data-testid=”foo”.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Note: Settings like the ones below:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;afterEach(() =&amp;gt; { // After each test, we reset the stubs and destroy the instance
  wrapper.unmount();
  vi.resetAllMocks();
});
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;&lt;p&gt;can be moved to external files and connected in the vite.config.js settings as a global setting:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;// vite.config.js
export default defineConfig({
  test: {
    // ...
    setupFiles: ['path to your file'],
    // ...
  },
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;problem-with-unit-tests&quot;&gt;Problem with unit tests&lt;/h3&gt;
&lt;p&gt;Ultimately, unit tests help establish a contract between components. However, there's a downside: if we change the modal’s code, for example, its emitted events, the test for AddIncomingMail won’t fail. &lt;/p&gt;
&lt;p&gt;This is where integration tests (as mentioned earlier) come in, testing larger sections of the app. &lt;/p&gt;
&lt;p&gt;I haven’t fully implemented those tests yet, as I’m still thinking about the infrastructure and mocks (particularly for server requests), through a conditional &lt;a rel=&quot;nofollow&quot; href=&quot;https://mswjs.io/&quot;&gt;msw&lt;/a&gt;. However, there is a problem with maintaining the relevance of mocked responses (fixtures). Ideally, I'd like to use “Vitest browser mode” or “Playwright CT”, but these tools are still in their infancy. &lt;/p&gt;
&lt;p&gt;Start testing your code early and don’t treat testing as something separate from development. Yes, at first it will be tough, and yes, it will continue to be tough, but soon enough, you’ll just get used to it.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Author: Dmitry Simonov, Frontend Developer at ByteMinds&lt;/em&gt;&lt;/p&gt;
</description>
<category>Web Dev</category>
<guid isPermaLink="true">https://coderlegion.com/1682/how-i-started-writing-unit-tests-for-vue-components</guid>
<pubDate>Sun, 30 Mar 2025 02:37:53 +0000</pubDate>
</item>
<item>
<title>Unit Testing in Python</title>
<link>https://coderlegion.com/211/unit-testing-in-python</link>
<description>&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt; There are two types of developers in the programming world. The first one writes code and walks away, does not watch it run. They assume everything will go according to plan. There is the second type, who is &lt;strong&gt;writing unit tests&lt;/strong&gt;. With Python built-in test modules, you can &lt;strong&gt;effectively write code to test your software's&lt;/strong&gt; modules. It will give you peace of mind that eludes all too many programmers. Most companies and teams require their &lt;strong&gt;code to be thoroughly examined&lt;/strong&gt;. This &lt;strong&gt;saves&lt;/strong&gt; you a lot of time and also gives you confidence that your updates and refactoring don't have any &lt;strong&gt;unintended consequences&lt;/strong&gt; to break your code execution in a way.&lt;br&gt; So, in this article, I will cover the details of the basic understanding of unit testing, its importance, the key principles and benefits while writing code in &lt;a rel=&quot;nofollow&quot; href=&quot;https://coderlegion.com/104/python-getting-started&quot; target=&quot;_blank&quot;&gt;Python&lt;/a&gt;, how to write tests, its environment setup, and some best practices.&lt;/p&gt;
&lt;h2 style=&quot;margin: 0.5;&quot;&gt;Understanding Unit Testing&lt;/h2&gt;
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;Definition of Unit Testing&lt;/h3&gt; 
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;Unit testing is the practice or software testing framework used for &lt;strong&gt;examining the smallest piece of code&lt;/strong&gt;, referred to as a unit, and testing them individually to check if they are functioning as intended. Additionally, it isolates the smallest piece of testable software from the remainder of the code to determine if it behaves as expected and according to the requirement in operation.&lt;/p&gt;
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;Purpose of Unit Testing&lt;/h3&gt;
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;The primary purpose of unit testing is to verify each unit or component of the software individually and whether each functionality is &lt;strong&gt;working based on the user's requirements&lt;/strong&gt;. It encourages the developer to write cleaner and modular code that is independent of other modules. Using unit testing, you can easily maintain the software application over time.&lt;/p&gt;
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;Key Principles of Unit Testing&lt;/h3&gt;
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;Unit testing is the &lt;strong&gt;initial phase of software testing&lt;/strong&gt;, where an individual unit or component of the software is tested against the needs and requirements of the user. Several key principles help us to ensure the correct testing mechanism so that each unit performs the expected designed functionality. Here are the principles:&lt;/p&gt; 
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;1. Isolation&lt;/h3&gt;
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;The first fundamental testing principle is isolation, which means that &lt;strong&gt;each unit that has undergone testing&lt;/strong&gt; should not be independent of other modules. Each functionality is tested separately, like the module having one specific functionality. It ensures that the issue in one module does not affect the working of another module. So, make sure each tested unit is isolated.&lt;/p&gt;
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;2. Independence&lt;/h3&gt;
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;Independence is another principle that requires consideration while testing. It means that each &lt;strong&gt;unit test is independent&lt;/strong&gt; of the other unit test. In this way, the test failure of one unit does not impact the execution of another unit. Also, it ensures that the unit testing is done in any order and that one module testing is not waiting for another unit result.&lt;/p&gt;
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;3. Repeatable&lt;/h3&gt;
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;This principle is most widely used for automated test suites, where &lt;strong&gt;results should be consistent&lt;/strong&gt; irrespective of how many times we run the unit test. Therefore, the unit test code should be repeatable.&lt;/p&gt;
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;4. Fast&lt;/h3&gt; 
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;Each unit test should be able to &lt;strong&gt;quickly identify the defect&lt;/strong&gt; when the testing fails. This principle ensures the fastest way of testing the individual unit instead of testing the whole application at once.&lt;/p&gt;
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;Benefits of Unit Testing&lt;/h3&gt; 
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;1. Early Bug Detection&lt;/h3&gt;
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt; Unit testing helps us &lt;strong&gt;find software bugs early&lt;/strong&gt;. It is carried out by developers who test individual code prior to integrating multiple modules. Bugs or issues are identified very early and resolved &lt;strong&gt;without impacting&lt;/strong&gt; other pieces of code, thus facilitating early detection of errors in the software. 
&lt;/p&gt;&lt;h3 style=&quot;margin: 0.5;&quot;&gt;2. Simplified Debugging&lt;/h3&gt;
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;Unit testing also makes &lt;strong&gt;debugging easier and quicker&lt;/strong&gt;. It helps simplify the &lt;a rel=&quot;nofollow&quot; href=&quot;https://coderlegion.com/257/python-debugging-techniques&quot; target=&quot;_blank&quot;&gt;debugging&lt;/a&gt; process, if a test fails only then the latest changes made in the code need to be debugged.&lt;/p&gt; 
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;3. Code Documentation&lt;/h3&gt; 
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt; Code documentation mostly shows how little code documentation gets written. Unit testing can make the documentation &lt;strong&gt;burden a little easier&lt;/strong&gt; by encouraging better coding practices and leaving behind the piece of code that describes what your program is going to achieve.&lt;/p&gt; 
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;4. Refactoring Confidence&lt;/h3&gt;
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;It makes the coding process more agile when you add more and more features to software applications and sometimes need to change the old design and code. However, &lt;strong&gt;changing the already-tested code&lt;/strong&gt; is both risky and extremely costly. If we have a unit test in place, then we can proceed with refactoring very confidently to verify each part of a code is working properly.&lt;/p&gt;
&lt;h2 style=&quot;margin: 0.5;&quot;&gt;Getting Started with Unit Testing in Python&lt;/h2&gt; 
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;1. Introduction to Python's Built-in Unit Testing Framework: unittest &lt;/h3&gt;
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;Python has introduced &lt;strong&gt;two main modules&lt;/strong&gt; for performing unit testing, i.e. &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.python.org/3/library/unittest.html&quot; title=&quot;file&quot;&gt;unittest&lt;/a&gt; and &lt;strong&gt;pytest&lt;/strong&gt;. The unitest module is part of the Python standard library. So, there is no need to pip install it. It is a testing framework that allows us to write and execute unit tests for our Python modules. It has a set of classes and methods that provide us the functionality to write unit tests and execute them, working based on object-oriented concepts.&lt;/p&gt;
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;2. Setting up a project for Unit Testing&lt;/h3&gt; 
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;Before starting the technical details to understand the unit testing, make sure you installed Python with the VS Code on your machine and also set up the project in the necessary directory. So, let's get started.&lt;/p&gt;
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;2-1. Project Structure&lt;/h3&gt; 
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;First, create a directory and name it according to your choice. Then, create &lt;strong&gt;two subdirectories&lt;/strong&gt; in it; the first one is named src, used for saving the main source code without unit testing. The second one is named test, where you put the unit test code. So, this is the way to set up the project in Python using the necessary directory structure. Let's say we have the following project structure:&lt;/p&gt;
![][1]

&lt;h3 style=&quot;margin: 0.5;&quot;&gt;2-2. Installation of necessary Libraries&lt;/h3&gt; 
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;As discussed above, unittest is the testing framework and is part of the Python standard library. So, there is &lt;strong&gt;no need for additional installation&lt;/strong&gt;. Also, just make sure that the python is installed on your computer. &lt;/p&gt;

&lt;h3 style=&quot;margin: 0.5;&quot;&gt; Unit Testing Algorithm&lt;/h3&gt; 
![][2]

&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;Let us see a simple algorithm of unit testing in which you can start by &lt;strong&gt;writing test code&lt;/strong&gt; and adding these tests to the test suit. Then you run the unit test, if the &lt;strong&gt;test passes&lt;/strong&gt;, you add one more test or add to the &lt;strong&gt;next level of testing&lt;/strong&gt;. In case of test failure, you make the &lt;strong&gt;necessary changes and execute the unit test again&lt;/strong&gt; but failed. However, you &lt;strong&gt;repeat the cycle and make changes&lt;/strong&gt; until the code is perfectly working and returns the expected results. On the other hand, after making changes if the test passes, you can &lt;strong&gt;add it to the test suite&lt;/strong&gt; and move on to the next unit test. After completing all the tests and checking the functionality you can &lt;strong&gt;stop the testing&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;3. Writing your First Unit Test&lt;/h3&gt; 
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;3-1. Creating Source Code&lt;/h3&gt; 
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;Before demonstrating the testing, you require the source code upon which unit testing is performed. Suppose you are making a simple calculator that performs basic math operations like addition, subtraction, multiplication, and division. All these operations are written in the file named calculator.py, which is placed in the src directory. Let's move towards the coding part.&lt;/p&gt;
    print(&quot;SIMPLE CALCULATOR&quot;) 
    print(&quot;Having operation '+', '-', '*' and '/'&quot;) 
    class calculator: 
        def addition(num1, num2): #function for addition  
            num3 = num1 + num2  
            return num3   
        def subtraction(num1, num2): #function for subtraction  
            num3 = num1 - num2 
            return num3    
        def multiplication(num1, num2): #function for multiplication 
            return num1 * num2     
        def division(num1, num2): #function for division  
            num3 = num1 / num2 
            return num3 
        result1 = addition(10, 5) 
        result2 = multiplication(5, 5) 
        print(&quot;Addition of two numbers:&quot; , result1) 
        print(&quot;Multiplication of two numbers:&quot; , result2) 

&lt;h3 style=&quot;margin: 0.5;&quot;&gt;3-2. Writing Test Methods&lt;/h3&gt; 
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;Now, we want to test the methods inside the above code. For that, we need to &lt;strong&gt;import the unittest module&lt;/strong&gt;, then required to create a test method which is based on the &lt;strong&gt;base class TestCase&lt;/strong&gt; containing functions for performing unit testing.&lt;/p&gt;
    import unittest #importing the module
    from src_code.calculation import calculator # importing the function form the main class
    
    class Testing(unittest.TestCase): #used the base class for creating testing subclass
        def test_addition(self): #create the test function
            self.assertEqual(calculator.addition(5,5), 10) #takes the values and its answer and check its correctness
            self.assertEqual(calculator.addition(6,7), 13)
        
        def test_multiplication(self): #another function
            self.assertEqual(calculator.multiplication(5,5), 25) #takes the values and its answer and check its correctness
            self.assertEqual(calculator.multiplication(4,2),8)
    
    if __name__ == '__main__': #used to class the main class of unittest
        unittest.main()

&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;In the above code, addition() and multiplication() functions of calculator.py are tested. To achieve this, we have to do the following:&lt;/p&gt; 
&lt;ol&gt;
&lt;li style=&quot;text-align: justify; margin: 1;&quot;&gt;Import the &lt;strong&gt;unittest library&lt;/strong&gt; and the calculator class from calculator.py.&lt;/li&gt;
&lt;li style=&quot;text-align: justify; margin: 1;&quot;&gt;Then, &lt;strong&gt;create the testing method&lt;/strong&gt; for both addition() and multiplication() methods using the calculator instance.&lt;/li&gt;
&lt;li style=&quot;text-align: justify; margin: 1;&quot;&gt;Use the &lt;strong&gt;assertEqual function&lt;/strong&gt; that checks that the given values output or the expected output should be the same and equal.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;3-3. Running Tests&lt;/h3&gt;
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;For running the unit test, we use &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.python.org/3/library/unittest.html#unittest.TestCase&quot; title=&quot;file&quot;&gt;unittest.main()&lt;/a&gt;, which will execute the test when the program runs. It will displays the output when the program tested successfully but, if the program fails, the compiler will highlight the error in the terminal and show that the testing failed.&lt;/p&gt; 
![][3]

&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;If we &lt;strong&gt;change the excepted output&lt;/strong&gt; values of the multiplication() function, then testing fails and this will be displayed in the terminal: &lt;/p&gt;
![][4]

&lt;div class=&quot;div-blue&quot;&gt;  
&lt;span class=&quot;alert-header&quot;&gt;Note:&lt;/span&gt;  
&lt;span class=&quot;alert-body&quot;&gt;Remember, it is the convention that all the testing methods should start with the keyword test_ because this way unittest can easily identify the method that needs to be executed.  
&lt;/span&gt; 
&lt;/div&gt;
&lt;h2 style=&quot;margin: 0.5;&quot;&gt; Anatomy of a Unit Test&lt;/h2&gt; 
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;1. Test fixture setup and teardown&lt;/h3&gt; 
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;After understanding the basics of the unittest module, we move towards the more &lt;strong&gt;advanced concepts of the testing&lt;/strong&gt; framework used for optimizing the code. Test fixture &lt;strong&gt;setup and teardown&lt;/strong&gt; are widely used for &lt;strong&gt;initializing and cleaning up&lt;/strong&gt; the task before and after the test execution. Suppose we create a class called employee having all employee details. Now, we want to test the emails and payment increment of each employee, for that, we have to write the test code for each employee, and it's hectic. Also, it creates redundant code repeatedly. So, to resolve this problem, I am going to use two components in the unittest modules used for optimizing the code.&lt;/p&gt;
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;1-1. setUp() method&lt;/h3&gt; 
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt; The setUp() method will run its code &lt;strong&gt;before every single test is executed&lt;/strong&gt;. It is helpful when you have to perform the same task again and again in each test function. Therefore, placing that piece of code in the setUp() function will help you in redundancy reduction and optimization. Let's move towards the coding part for better understanding.&lt;/p&gt;
&lt;em&gt;employee.py&lt;/em&gt;

    class Employee: #employee class
        increment_amt = 1.05 #variable with increment value
    
        def __init__(self, name, pay): #function for taking values 
            self.name = name
            self.pay = pay
        
        @property
        def email(self): #email function 
            return '{}@gmail.com'.format(self.name)
        
        def increment(self): #function of incremeting the payment
            self.pay = int(self.pay * self.increment_amt)

&lt;em&gt;emp_testing.py&lt;/em&gt;

    import unittest #importing the module
    from src_code.employee import Employee
    
    class Testing(unittest.TestCase): #used the base class for creating testing subclass
        def setUp(self): #setup the resource before each execution
            self.emp1 = Employee('john', 50000)
            self.emp2 = Employee('stephen', 60000)
        
        def test_email(self):
            self.assertEqual(self.emp1.email, '*Emails are not allowed*')
            self.assertEqual(self.emp2.email, '*Emails are not allowed*')
        
        def test_increment(self):
            self.emp1.increment()
            self.emp2.increment()
            self.assertEqual(self.emp1.pay, 52500)
            self.assertEqual(self.emp2.pay, 63000)      
    if __name__ == '__main__': #used to class the main class of unittest
        unittest.main()

![][5]

&lt;h3 style=&quot;margin: 0.5;&quot;&gt;1-2. tearDown() method&lt;/h3&gt;
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;The tearDown() will run its code &lt;strong&gt;after the test execution&lt;/strong&gt;. It is for releasing the resources after using it like database connection or some cleanup activities.&lt;/p&gt;

    def setUp(self): #setup the resource before each execution
        self.emp1 = Employee('john', 50000)
        self.emp2 = Employee('stephen', 60000)
    
    def tearDown(self): #deleting the employee
        del self.emp1

&lt;h3 style=&quot;margin: 0.5;&quot;&gt;2. Writing Assertions&lt;/h3&gt;
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;2-1. Using Assert Statements&lt;/h3&gt; 
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt; In Python, the assert is the built-in statement used for &lt;strong&gt;checking the conditions&lt;/strong&gt;. If the condition is true, it will not show anything but in case of error or the false condition, it will raise the error. Most assert statements are considered as exceptions and errors, but developers prefer their utilization for testing and debugging purposes.&lt;/p&gt;

    n = 1 
    assert 1 &amp;lt; n, 'This condition is false'  #checks and print only if its false 
&lt;strong&gt;Output&lt;/strong&gt;
![][6]
 
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;2-2. Common Assert Methods&lt;/h3&gt;
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;As we discussed the assert statement above, there is no need to use it separately in the program. The unittest module contains the base class TesCase and provides all the assert functions that work exactly like assert statements without detailed coding. These methods are used within the test method to check whether the resulting output matches the excepted output. Here, I will discuss the common assert methods provided by the TestCase class of unittest.&lt;/p&gt;
![][7]

&lt;div class=&quot;div-green&quot;&gt;  
&lt;span class=&quot;alert-header&quot;&gt;Tip:&lt;/span&gt;  
&lt;span class=&quot;alert-body&quot;&gt;Always try to avoid testing the external dependencies like databases, files, or network connections because they slow down tests and make them brittle.  
&lt;/span&gt; 
&lt;/div&gt;
&lt;div class=&quot;div-faq&quot; style=&quot;margin-bottom: 5px; margin-top: 2px;&quot;&gt; 
&lt;span class=&quot;faq-header&quot; style=&quot;font-weight: bold; color: dark-gray;&quot;&gt;FAQs&lt;/span&gt; 
&lt;span class=&quot;faq-body&quot; style=&quot;margin-top: 1px; margin-bottom: 5px;&quot;&gt; Q: What is the unittest.TestCase in the unittest module? &lt;br&gt;A: unittest.TestCase is the base class of the unittest module that serves as a container for all individual test&lt;/span&gt;  
&lt;span class=&quot;faq-body&quot; style=&quot;margin-top: 1px; margin-bottom: 5px;&quot;&gt; Q: When should I start writing the &lt;a rel=&quot;nofollow&quot; href=&quot;https://coderlegion.com/215/testing-in-python-writing-test-cases-with-unittest&quot; target=&quot;_blank&quot;&gt;test cases&lt;/a&gt;? &lt;br&gt;A: The best approach is to write when you are developing the application because it ensures that application is free of bugs from the early stage.&lt;/span&gt;  
&lt;/div&gt;
&lt;h2 style=&quot;margin: 0.5;&quot;&gt;Wrapping Up&lt;/h2&gt;
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt; To sum up, we discussed the basics of unit testing and got to know its &lt;strong&gt;importance in the development and maintenance&lt;/strong&gt; of software. We also learn the unit testing techniques by using the coding examples. It shows that unit testing is a very crucial phase before other testing. It also ensures that the &lt;strong&gt;individual module is error-prone&lt;/strong&gt; and modular. Developer needs to understand that the use of unit testing during the application developement will save most of their time and &lt;strong&gt;ensure the quality of software&lt;/strong&gt;. I hope this guide is helpful for you. Also, if you have any questions or concerns, then feel free to ask and give feedback. Thank you for following this guide. Happy Coding!&lt;/p&gt;
&lt;hr&gt;
&lt;h2 style=&quot;margin: 0.5;&quot;&gt; Reference&lt;/h2&gt;   
&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.python.org/3/library/unittest.html&quot; title=&quot;file&quot;&gt;Unit Testing&lt;/a&gt; 


  [1]: https://logiclair.org/?qa=blob&amp;amp;qa_blobid=16541390965964414061
  [2]: https://logiclair.org/?qa=blob&amp;amp;qa_blobid=4202928536661986523
  [3]: https://logiclair.org/?qa=blob&amp;amp;qa_blobid=7841557182954355083
  [4]: https://logiclair.org/?qa=blob&amp;amp;qa_blobid=9280295931013992206
  [5]: https://logiclair.org/?qa=blob&amp;amp;qa_blobid=1643797813287049192
  [6]: https://logiclair.org/?qa=blob&amp;amp;qa_blobid=3774790010506432385
  [7]: https://logiclair.org/?qa=blob&amp;amp;qa_blobid=12721698954172678740
</description>
<category>Testing</category>
<guid isPermaLink="true">https://coderlegion.com/211/unit-testing-in-python</guid>
<pubDate>Thu, 04 Apr 2024 23:40:16 +0000</pubDate>
</item>
</channel>
</rss>