<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged unittest</title>
<link>https://coderlegion.com/tag/unittest</link>
<description>Powered by Question2Answer</description>
<item>
<title>Refactoring Go API Unit Tests: Breaking Down the Testing Monolith</title>
<link>https://coderlegion.com/20400/refactoring-go-api-unit-tests-breaking-down-the-testing-monolith</link>
<description>&lt;h4 id=&quot;the-concept&quot;&gt;The Concept&lt;/h4&gt;
&lt;p&gt;When building backend APIs in Go, testing isn't just about code coverage, it's about long-term maintainability. As an application grows, a naive approach to unit testing can lead to &quot;testing monoliths&quot; where test setup, mocking, HTTP routing, and core business logic verification are jammed into a single, massive file.&lt;/p&gt;
&lt;p&gt;To keep a codebase agile, your testing architecture must mirror the separation of concerns found in your production code. This means isolating the code that handles incoming network requests from the code that executes your core domain logic.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;the-what&quot;&gt;The What&lt;/h4&gt;
&lt;p&gt;Initially, the testing structure for the API lived entirely within a single, monolithic &lt;code&gt;*_test.go&lt;/code&gt; file. Inside this file, everything was dumped together: Only service-layer assertions no HTTP request simulation, and handwritten mock structs for both the repository and service layers.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const UUID = &quot;12345678-1234-5678-1234-567890123456&quot;

type StockMovementTest struct {
GetStockMovementsFunc         func(ctx context.Context, filters dto.BaseFilters) ([]models.StockMovement, int, error)
}

func (m *StockMovementTest) GetStockMovements(ctx context.Context, q dto.BaseFilters) ([]models.StockMovement, int, error) {
if m.GetStockMovementsFunc != nil {
return m.GetStockMovementsFunc(ctx, q)
}

return nil, 0, nil
}

func NewTestStockMovement(testStockMovementRepo *StockMovementTest) stock_movements.StockMovementService {
emailSvc := mocks.NewTestEmailService()
_, auditLogSvc := mocks.NewTestAuditService()
awsSvc := mocks.NewTestAWSService()

return stock_movements.NewStockMovementService(testStockMovementRepo, emailSvc, nil, auditLogSvc, awsSvc)
}

func TestGetStockMovements(t *testing.T) {
testStockMovementRepo := &amp;amp;StockMovementTest{}
testStockMovementSvc := NewTestStockMovement(testStockMovementRepo)

t.Run(&quot;Get StockMovements&quot;, func(t *testing.T) {
testStockMovementRepo.GetStockMovementsFunc = func(ctx context.Context, q dto.BaseFilters) ([]models.StockMovement, int, error) {
CheckStockMovementQuery(t, q)
return []models.StockMovement{{ProductID: 1}}, 1, nil
}

query := dto.Query{Search: &quot;test&quot;, Limit: 10, Offset: 2, Sort: &quot;change_amount ASC&quot;}
_, _, err := testStockMovementSvc.GetStockMovements(context.Background(), query)

if err != nil {
t.Errorf(&quot;Expected no error, got %v&quot;, err)
}
})
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;the-why&quot;&gt;The Why&lt;/h4&gt;
&lt;p&gt;While a single-file approach works for small projects, it quickly becomes an anti-pattern due to two major pain points:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Code Bloating:&lt;/strong&gt; A single file containing setup, table-driven test cases, and verbose mock definitions quickly grows to thousands of lines, making it incredibly difficult to navigate and maintain.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Circular Dependencies (Cyclic Imports):&lt;/strong&gt; In Go, packages cannot import each other transitively. When mocks, domain logic, and HTTP transport layers are tightly coupled in tests, you risk hitting compilation errors because the boundaries between your database, service, and handler packages become blurred.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Separating these concerns ensures that your tests remain clean, compile quickly, and scale alongside your features.&lt;/p&gt;
&lt;h4 id=&quot;the-how&quot;&gt;The How&lt;/h4&gt;
&lt;p&gt;To resolve this, the monolithic test file was refactored into a modular structure by breaking it down into three distinct components: &lt;code&gt;mock.go&lt;/code&gt;, &lt;code&gt;*_service_test.go&lt;/code&gt;, and &lt;code&gt;*_handler_test.go&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;📂 package_test/
├── 📄 mock.go              # Shared mock definitions for service &amp;amp; repository layers
├── 📄 *_service_test.go    # Pure business logic unit tests
└── 📄 *_handler_test.go    # HTTP, routing, and request/response validation tests

&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;// mock.go

type MockAuthService struct {
//
}

func (m *MockAuthService) GenerateToken(userID int64) (string, error) {
return &quot;&quot;, nil
}

func (m *MockAuthService) ParseToken(token string) (int64, error) {
return 0, nil
}

func (m *MockAuthService) Login(ctx context.Context, req LoginRequest) (string, error) {
return &quot;&quot;, nil
}

func (m *MockAuthService) Register(ctx context.Context, req RegisterRequest) error {
return nil
}

type MockAuthRepository struct {
GetUsernameOrEmailFunc func(ctx context.Context, username string) (*models.Users, error)
RegisterFunc           func(ctx context.Context, user *models.Users) error
}

func (m *MockAuthRepository) Register(ctx context.Context, user *models.Users) error {
if m.RegisterFunc != nil {
return m.RegisterFunc(ctx, user)
}

return nil
}

func (m *MockAuthRepository) GetUsernameOrEmail(ctx context.Context, username string) (*models.Users, error) {
if m.GetUsernameOrEmailFunc != nil {
return m.GetUsernameOrEmailFunc(ctx, username)
}

return &amp;amp;models.Users{}, nil
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;// *_service_test.go

var testAuthRepo = &amp;amp;auth.MockAuthRepository{}
var testAuthSvc = NewTestAuth(testAuthRepo)

func NewTestAuth(testAuthRepo *auth.MockAuthRepository) auth.AuthService {
config := &amp;amp;config.Config{JWTSecretKey: &quot;airconcure_jwt_key&quot;}

return auth.NewAuthService(testAuthRepo, config)
}

func TestAuthServiceLogin(t *testing.T) {
t.Run(&quot;login credentials&quot;, func(t *testing.T) {
testAuthRepo.GetUsernameOrEmailFunc = func(ctx context.Context, username string) (*models.Users, error) {
passwordHash, _ := bcrypt.GenerateFromPassword([]byte(&quot;!Abc1234&quot;), bcrypt.DefaultCost)
user := &amp;amp;models.Users{
ID:       1,
Username: &quot;test_account&quot;,
Email:    &quot;*Emails are not allowed*&quot;,
Password: string(passwordHash),
}

return user, nil
}

req := auth.LoginRequest{
Username: &quot;rdev&quot;,
Password: &quot;!Abc1234&quot;,
}

_, err := testAuthSvc.Login(context.Background(), req)
if err != nil {
t.Errorf(&quot;Expected no error, got %v&quot;, err)
}
})
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;// *_handler_test.go

var testAuthHandler = auth.NewAuthHandler(&amp;amp;auth.MockAuthService{})

func TestAuthHandlerLogin(t *testing.T) {
type loginRequest struct {
Username string `json:&quot;username&quot;`
Password string `json:&quot;password&quot;`
}

tests := []struct {
name           string
url            string
requestBody    any
expectedStatus int
}{
{
name: &quot;complete login credentials&quot;,
url:  &quot;/login&quot;,
requestBody: loginRequest{
Username: &quot;rdev&quot;,
Password: &quot;!Abc1234&quot;,
},
expectedStatus: http.StatusOK,
},
{
name: &quot;login no password&quot;,
url:  &quot;/login&quot;,
requestBody: loginRequest{
Username: &quot;rdev&quot;,
Password: &quot;&quot;,
},
expectedStatus: http.StatusBadRequest,
},
{
name: &quot;login password less than minimum required&quot;,
url:  &quot;/login&quot;,
requestBody: loginRequest{
Username: &quot;rdev&quot;,
Password: &quot;1234&quot;,
},
expectedStatus: http.StatusBadRequest,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx, w := helpers.SetupJSONTestContext(t, http.MethodPost, tt.url, tt.requestBody)

testAuthHandler.Login(ctx)

if w.Code != tt.expectedStatus {
t.Errorf(&quot;Login() status = %d, resp = %v, want %d&quot;, w.Code, w.Body, tt.expectedStatus)
}
})
}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h5 id=&quot;1-centralizing-mocks-mock-go-&quot;&gt;1. Centralizing Mocks (&lt;code&gt;mock.go&lt;/code&gt;)&lt;/h5&gt;
&lt;p&gt;Instead of rewriting or copy-pasting mock implementations across multiple test files, all repository and service mock structs are declared once inside a dedicated &lt;code&gt;mock.go&lt;/code&gt; file within the package. This acts as a single source of truth for test doubles.&lt;/p&gt;
&lt;h5 id=&quot;2-testing-the-business-logic-service-test-go-&quot;&gt;2. Testing the Business Logic (&lt;code&gt;*_service_test.go&lt;/code&gt;)&lt;/h5&gt;
&lt;p&gt;This file focuses strictly on testing the &quot;under-the-hood&quot; domain logic. Because the database/repository layer is mocked out via &lt;code&gt;mock.go&lt;/code&gt;, these tests run entirely in-memory and are incredibly fast. They validate:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Data validation rules and edge cases.&lt;/li&gt;
&lt;li&gt;Handling of incorrect data types or malformed payloads.&lt;/li&gt;
&lt;li&gt;Domain-specific error handling and state transitions.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;3-testing-the-http-transport-layer-handler-test-go-&quot;&gt;3. Testing the HTTP Transport Layer (&lt;code&gt;*_handler_test.go&lt;/code&gt;)&lt;/h5&gt;
&lt;p&gt;This file is dedicated to verifying how the API interacts with the outside world. It uses Go's &lt;code&gt;net/http/httptest&lt;/code&gt; package to simulate client requests, utilizing the service mocks so it doesn't trigger actual business logic. These tests validate:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HTTP status codes (e.g., &lt;code&gt;200 OK&lt;/code&gt;, &lt;code&gt;400 Bad Request&lt;/code&gt;, &lt;code&gt;429 Too Many Requests&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;JSON serialization and deserialization.&lt;/li&gt;
&lt;li&gt;Query parameters, URL parameters, and headers.&lt;/li&gt;
&lt;li&gt;Middleware execution, such as rate limiters and authentication checks.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id=&quot;the-trade-offs&quot;&gt;The Trade-offs&lt;/h4&gt;
&lt;p&gt;Like any architectural decision, moving to a multi-file testing structure comes with balancing factors:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;High Scannability:&lt;/strong&gt; Developers looking for a routing bug only need to open the handler test, while those fixing a calculation bug can go straight to the service test.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reduced Friction:&lt;/strong&gt; Isolating the mocks prevents cyclic imports, keeping the Go compiler happy.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Clear Boundaries:&lt;/strong&gt; It enforces discipline, ensuring you don't accidentally test HTTP mechanics inside a business logic test.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Boilerplate Overhead:&lt;/strong&gt; Managing multiple files and orchestrating mocks requires slightly more upfront configuration and file management.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mock Maintenance:&lt;/strong&gt; If a service interface changes, the central &lt;code&gt;mock.go&lt;/code&gt; file must be manually updated (unless you adopt a code-generation tool like &lt;code&gt;mockery&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id=&quot;in-layman-s-terms&quot;&gt;In Layman's Terms&lt;/h4&gt;
&lt;p&gt;Imagine you run a busy restaurant.&lt;/p&gt;
&lt;p&gt;Originally, your test kitchen had one giant manual that crammed the cook’s recipes, the waiter’s serving rules, and cardboard cutouts of fake customers all onto the same page. It was crowded and confusing.&lt;/p&gt;
&lt;p&gt;With this new approach, you split that manual into three neat folders:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The Prop Room (&lt;code&gt;mock.go&lt;/code&gt;): This is where you keep all your cardboard cutouts (fake databases and fake chefs) so you can reuse them whenever you need to practice.&lt;/li&gt;
&lt;li&gt;The Kitchen Manual (&lt;code&gt;*_service_test.go&lt;/code&gt;): This is where you test the food itself. Does it taste right? Is it missing an ingredient? You don't care how the waiter delivers it; you just care that the recipe works perfectly.&lt;/li&gt;
&lt;li&gt;The Dining Room Manual (&lt;code&gt;*_handler_test.go&lt;/code&gt;): This is where you test the customer experience. Did the waiter smile? Was the bill calculated correctly? Is the host stopping too many people from rushing the door at once (rate limiting)? You don't care how the kitchen cooked the food here; you just care that the service at the table is seamless.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h4&gt;
&lt;p&gt;While software architecture preferences always vary depending on team conventions, decoupling your tests by responsibility is a proven strategy for Go applications. By isolating your HTTP logic from your business logic and centralizing your mocks, you eliminate code bloat, wipe out cyclic imports, and create a test suite that is easy to read, navigate, and maintain.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/20400/refactoring-go-api-unit-tests-breaking-down-the-testing-monolith</guid>
<pubDate>Fri, 12 Jun 2026 13:40:37 +0000</pubDate>
</item>
<item>
<title>[BOOK REVIEW] Meszaros G., xUnit Test Patterns (2007)</title>
<link>https://coderlegion.com/7304/book-review-meszaros-g-xunit-test-patterns-2007</link>
<description>&lt;p&gt;This is the teaser post of the &lt;a rel=&quot;nofollow&quot; href=&quot;http://%20https://valentineshi.dev/content/book-reviews/x8REmtO9TWGq-3r_SDHMvQ/meszaros-g-xunit-test-patterns-2007&quot;&gt;original&lt;/a&gt; review that is pretty detailed, containing images and diagrams.&lt;/p&gt;
&lt;h2 id=&quot;meszaros-g-xunit-test-patterns-2007-&quot;&gt;Meszaros G., xUnit Test Patterns (2007)&lt;/h2&gt;
&lt;p&gt;Extract&lt;/p&gt;
&lt;p&gt;This &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.amazon.com/xUnit-Test-Patterns-Refactoring-Code/dp/0131495054&quot;&gt;book&lt;/a&gt; is essential language-agnostic source to make your TDD delivering principal values: maintainable test code, joyful &lt;abbr title=&quot;System Under Test&quot;&gt;SUT&lt;/abbr&gt; refactorings, and zero product defects.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Contents&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Summary&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Concepts&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Goals of Test Automation&lt;/li&gt;
&lt;li&gt;Testing Philosophy&lt;/li&gt;
&lt;li&gt;Principles of Test Automation&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Practice&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Test Smells&lt;/li&gt;
&lt;li&gt;Test Automation Strategy&lt;/li&gt;
&lt;li&gt;xUnit Basics&lt;/li&gt;
&lt;li&gt;Test Fixtures&lt;/li&gt;
&lt;li&gt;Result Verification&lt;/li&gt;
&lt;li&gt;Test Doubles&lt;/li&gt;
&lt;li&gt;Test Organization&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Testing with Databases&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Issues with Testing with Databases&lt;/li&gt;
&lt;li&gt;Testing without Databases&lt;/li&gt;
&lt;li&gt;Testing the Database&lt;/li&gt;
&lt;li&gt;Database Patterns&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A Roadmap to Effective Test Automation&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Test Automation Difficulty&lt;/li&gt;
&lt;li&gt;Roadmap to Highly Maintainable Automated Tests&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Remaining Patterns&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;summary&quot;&gt;Summary&lt;/h3&gt;
&lt;p&gt;While &lt;a rel=&quot;nofollow&quot; href=&quot;https://valentineshi.dev/content/book-reviews/JpuwEWmVTg2tQBf-iIL94Q/beck-k-tdd-by-example-2002&quot;&gt;TDD by Example&lt;/a&gt; is more conceptual, practically demonstrating only &lt;abbr title=&quot;Red, Green, Refactor&quot;&gt;TDD cycle&lt;/abbr&gt;, this one presents a much wider and very practical body of knowledge a software engineer must not miss.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;[INFO] [xUnit](&lt;a rel=&quot;nofollow&quot; href=&quot;https://en.wikipedia.org/wiki/XUnit&quot;&gt;https://en.wikipedia.org/wiki/XUnit&lt;/a&gt;) is the family of unit testing frameworks implementing unified specific approaches and test code patternsThe family includes test frameworks for &lt;abbr title=&quot;JUnit&quot;&gt;Java&lt;/abbr&gt;, &lt;abbr title=&quot;NUnit, xUnit.net&quot;&gt;C#,&lt;/abbr&gt;, &lt;abbr title=&quot;Vitest, Jest, Mocha&quot;&gt;JavaScript&lt;/abbr&gt;, &lt;abbr title=&quot;PHPUnit&quot;&gt;PHP&lt;/abbr&gt; to name a few.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Despite seemingly &lt;abbr title=&quot;948 pages&quot;&gt;heavy&lt;/abbr&gt;, The book is effectively organized and is a pleasure to absorb using my reviewSkim the diagrams and maps, take 1-2 techniques you like most and start applyingWhen hungry again return for moreWith time the book becomes a good foundational reference on testing.&lt;/p&gt;
&lt;p&gt;The review combines &quot;Part INarratives&quot; and &quot;Part IIIPatterns&quot; into a single space as they discuss the same at different level on granularityPart I introduces concepts, Part III provides implementation patternsOn top the review moves the more broad concepts (goals, philosophy and principles) up.&lt;/p&gt;
&lt;h3 id=&quot;concepts&quot;&gt;Concepts&lt;/h3&gt;
&lt;h4 id=&quot;goals-of-test-automation&quot;&gt;Goals of Test Automation&lt;/h4&gt;
&lt;p&gt;Tests should (p. 84):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Help us to improve quality and understand the SUT.&lt;/li&gt;
&lt;li&gt;Reduce (and not introduce) risk.&lt;/li&gt;
&lt;li&gt;Be easy to run, easy to write and maintain.&lt;/li&gt;
&lt;li&gt;Require minimal maintenance as the system evolves around them.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;testing-philosophy&quot;&gt;Testing Philosophy&lt;/h4&gt;
&lt;p&gt;(p. 94)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Write the tests first!&lt;/li&gt;
&lt;li&gt;Tests are examples (of SUT usage)!&lt;/li&gt;
&lt;li&gt;Usually write tests one at a time, but sometimes list all the tests one can think of as skeletons upfront.&lt;/li&gt;
&lt;li&gt;Outside-in development helps clarify which tests are needed for the next layer inward.&lt;/li&gt;
&lt;li&gt;Use primarily State Verification (p. 172, 525) but will resort to Behavior Verification (p. 531) when needed to get good code coverage.&lt;/li&gt;
&lt;li&gt;Perform fixture design on a test-by-test basis.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;principles-of-test-automation&quot;&gt;Principles of Test Automation&lt;/h4&gt;
&lt;p&gt;(p. 102)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Write the Tests First&lt;/li&gt;
&lt;li&gt;Design for Testability&lt;/li&gt;
&lt;li&gt;Use the Front Door First&lt;/li&gt;
&lt;li&gt;Communicate Intent&lt;/li&gt;
&lt;li&gt;Don’t Modify the SUT&lt;/li&gt;
&lt;li&gt;Keep Tests Independent&lt;/li&gt;
&lt;li&gt;Isolate the SUT&lt;/li&gt;
&lt;li&gt;Minimize Test Overlap&lt;/li&gt;
&lt;li&gt;Minimize Untestable Code&lt;/li&gt;
&lt;li&gt;Keep Test Logic Out of Production Code&lt;/li&gt;
&lt;li&gt;Verify One Condition per Test&lt;/li&gt;
&lt;li&gt;Test Concerns Separately&lt;/li&gt;
&lt;li&gt;Ensure Commensurate Effort and Responsibility&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;practice&quot;&gt;Practice&lt;/h3&gt;
&lt;h4 id=&quot;test-smells&quot;&gt;Test Smells&lt;/h4&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://valentineshi.dev/content/book-reviews/x8REmtO9TWGq-3r_SDHMvQ/meszaros-g-xunit-test-patterns-2007#test-smells&quot;&gt;continue at the original [review]&lt;/a&gt;&lt;/p&gt;
</description>
<category>Unit Testing</category>
<guid isPermaLink="true">https://coderlegion.com/7304/book-review-meszaros-g-xunit-test-patterns-2007</guid>
<pubDate>Thu, 13 Nov 2025 08:47:56 +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>Testing in Python: Writing Test Cases with unittest</title>
<link>https://coderlegion.com/215/testing-in-python-writing-test-cases-with-unittest</link>
<description>&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;After developing the software application, you want to check and verify the functionality of the software before releasing it onto the market. You likely want to ensure its &lt;strong&gt;functionality based on the prescribed requirements&lt;/strong&gt;. So, for that, a software testing framework is used here. Developers create multiple &lt;strong&gt;test cases&lt;/strong&gt; to perform software testing. So, in this article, we will cover the basics of test cases, their purpose, and characteristics along with the techniques of writing good test cases. Also, the ways of organizing and managing the test cases effectively.&lt;/p&gt;
&lt;h2 style=&quot;margin: 0.5;&quot;&gt;Importance of Test Case and unittest Module&lt;/h2&gt;
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;Now you are wondering about test cases. In simple terms, it's like a &lt;strong&gt;blueprint to ensure the robustness and performance&lt;/strong&gt; of the software application &lt;strong&gt;against diverse scenarios&lt;/strong&gt;. It is important to write test cases because testing is nothing without it, and they act as an &lt;strong&gt;overseer for software quality&lt;/strong&gt;. It provides a tester, the structured approach, to verify the software and make it &lt;strong&gt;error-prone before delivering it to the user&lt;/strong&gt;. All this can be achieved by using the Python &lt;a rel=&quot;nofollow&quot; href=&quot;https://coderlegion.com/217/mastering-importing-modules-in-python&quot; target=&quot;_blank&quot;&gt;module&lt;/a&gt; i.e. unittest.&lt;/p&gt;
&lt;h2 style=&quot;margin: 0.5;&quot;&gt;Understanding Test Cases&lt;/h2&gt; 
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;1. Definition of Test Cases&lt;/h3&gt;  
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;A test case is a set of &lt;strong&gt;conditions or actions&lt;/strong&gt; used for performing software testing on the application to &lt;strong&gt;verify the expected functionality&lt;/strong&gt; or features. It helps the testing team verify every part of the software to find bugs or errors beforehand. The test cases are written based on software requirements.&lt;/p&gt;
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;2. Purpose of Test Cases in Software Development&lt;/h3&gt;
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;Testing needs to be performed with proper planning, otherwise the tester or the user will not be satisfied with the software working. In test cases, testers &lt;strong&gt;design and document all conditions&lt;/strong&gt; in such a way that it covers all the scenarios before the testing phase. It has &lt;strong&gt;several key principles&lt;/strong&gt;, such as &lt;strong&gt;detecting errors&lt;/strong&gt; at early stages, helping to &lt;strong&gt;mitigate the risk of occurrence&lt;/strong&gt; in the future, and the detailed &lt;strong&gt;coverage for testing&lt;/strong&gt; the software in different environments.&lt;/p&gt;
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;3. Characteristics of Good Test Cases&lt;/h3&gt; 
&lt;ol&gt;
&lt;li style=&quot;text-align: justify; margin: 1;&quot;&gt;&lt;strong&gt;Clarity:&lt;/strong&gt; The tester should write test cases in an understandable language, providing clarity to all the stakeholders involved in the testing. They should be clear enough to understand each pre-step to perform the testing.&lt;/li&gt; 
&lt;li style=&quot;text-align: justify; margin: 1;&quot;&gt;&lt;strong&gt;Completeness:&lt;/strong&gt; The tester should write test cases concisely and in a structured way that covers all the scenarios that software can undergo. They should cover all the expected requirements and aspects of the software application.&lt;/li&gt; 
&lt;li style=&quot;text-align: justify; margin: 1;&quot;&gt;&lt;strong&gt;Independence:&lt;/strong&gt; Each test case should be independent of the other, which means the result of one test case does not affect the outcome of the other. This way, you can better facilitate the bugs in isolation.&lt;/li&gt;
&lt;li style=&quot;text-align: justify; margin: 1;&quot;&gt;&lt;strong&gt;Reliability:&lt;/strong&gt; Each test case should be reliable in verifying software functionalities because it provides extensive coverage for testing the software in diverse circumstances. That makes the test cases more reliable than the unplanned and manual testing.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;4. Benefits of Writing Test Cases&lt;/h3&gt; 
&lt;ol&gt;
&lt;li style=&quot;text-align: justify; margin: 1;&quot;&gt;&lt;strong&gt;Bug Detection:&lt;/strong&gt; Test cases help us to &lt;strong&gt;identify the bugs and defects at the early stages&lt;/strong&gt; of development. While executing the test cases, the tester can easily identify the loopholes or areas that need to be changed or updated. It ensures the system needs to be tested against multiple input values to get similar outcomes and track the bugs.&lt;/li&gt;
&lt;li style=&quot;text-align: justify; margin: 1;&quot;&gt;&lt;strong&gt;Regression Testing:&lt;/strong&gt; Changes are inevitable and need to be handled carefully &lt;strong&gt;without impacting the other functionality&lt;/strong&gt;. Therefore, detailed test cases allow the software tester to verify the new functionality and assess its impact on other functionalities by the changes. &lt;/li&gt;
&lt;li style=&quot;text-align: justify; margin: 1;&quot;&gt;&lt;strong&gt;Documentation:&lt;/strong&gt; The tester documents the test cases concisely and in a structured manner, having a specific pattern that includes the pre and post-conditions and all other key points needed while testing. That helps the tester to keep a &lt;strong&gt;track record of each bug and error&lt;/strong&gt; to show the software quality to the user.&lt;/li&gt;
&lt;li style=&quot;text-align: justify; margin: 1;&quot;&gt;&lt;strong&gt;Collaboration:&lt;/strong&gt; It also encourages &lt;strong&gt;collaboration between the team members&lt;/strong&gt; while writing and executing the test cases. Not only that, but you can get early feedback from the user by collaborating with them. &lt;/li&gt;
&lt;/ol&gt;
&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;Many developers prefer to use an automated CI/CD pipeline to catch the changes done in the application. It will help you in advance with regression testing.
&lt;/span&gt; 
&lt;/div&gt;
&lt;h2 style=&quot;margin: 0.5;&quot;&gt;Introduction to the unittest Module&lt;/h2&gt;
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;Overview of the unittest Module in Python&lt;/h3&gt; 
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;&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; is the automated testing library, introduced by Python for performing &lt;a rel=&quot;nofollow&quot; href=&quot;https://coderlegion.com/211/unit-testing-in-python&quot; target=&quot;_blank&quot;&gt;unit testing&lt;/a&gt;. It is the part of Python standard library that allows us to write and execute unit tests for our Python modules. Its working process is derived from OOP, having a set of classes and methods that provide us with the functionality to write tests and execute them.&lt;/p&gt;
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;Features of unittest&lt;/h3&gt; 
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;The unittest module offers developers many features that enable them to write robust, comprehensive, and maintainable test cases. The following key features are: &lt;/p&gt;
&lt;ul&gt;
&lt;li style=&quot;text-align: justify; margin: 1;&quot;&gt;&lt;strong&gt;Test Fixture:&lt;/strong&gt; In the unittest module, the test fixture represents the need to &lt;strong&gt;initialize and clean up the task&lt;/strong&gt; before and after the test execution.&lt;/li&gt;
&lt;li style=&quot;text-align: justify; margin: 1;&quot;&gt;&lt;strong&gt;Test Suite:&lt;/strong&gt; It consists of the &lt;strong&gt;collection of test cases&lt;/strong&gt; having similar tasks.&lt;/li&gt;
&lt;li style=&quot;text-align: justify; margin: 1;&quot;&gt;&lt;strong&gt;Test Discovery:&lt;/strong&gt; It is used for &lt;strong&gt;finding the test cases&lt;/strong&gt; within the directory without manual intervention and running them.&lt;/li&gt;  
&lt;li style=&quot;text-align: justify; margin: 1;&quot;&gt;&lt;strong&gt;Test case:&lt;/strong&gt; It consists of a set of conditions needed to &lt;strong&gt;check and verify the working of software functionalities&lt;/strong&gt;. &lt;/li&gt;
&lt;li style=&quot;text-align: justify; margin: 1;&quot;&gt;&lt;strong&gt;Test Runner:&lt;/strong&gt; It is a final component used for &lt;strong&gt;running and executing the test&lt;/strong&gt; and displaying the outcome to the user.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;History and Evolution of unittest&lt;/h3&gt;  
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;The unittest testing module is part of Python standard library. Its idea is from JUnit, which is a Java testing framework. As we know, the JUnit testing module is designed to provide an automated way of testing the individual modules of the Java application. Therefore, that idea is adapted by Python, providing the &lt;strong&gt;PyUnit framework&lt;/strong&gt; which was later evolved by Python 2.7 and added in the &lt;strong&gt;standard library as an unittest module&lt;/strong&gt; for the Python developer.&lt;/p&gt;
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;Advantages of Using unittest for Writing Test Cases&lt;/h3&gt;
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;Now that we have seen the history and features of the unittest module, let's see some advantages for writing better test cases.&lt;/p&gt;
&lt;ol&gt; 
&lt;li style=&quot;text-align: justify; margin: 1;&quot;&gt;Firstly, it is a &lt;strong&gt;built-in library&lt;/strong&gt; that contains all the &lt;a target=&quot;_blank&quot;&gt;functions&lt;/a&gt; and testing methods, so there is no need for separate installation. &lt;/li&gt;
&lt;li style=&quot;text-align: justify; margin: 1;&quot;&gt;The &lt;strong&gt;developers familiar with JUnit&lt;/strong&gt; will easily understand its working, as it is based on the JUnit framework.&lt;/li&gt;
&lt;li style=&quot;text-align: justify; margin: 1;&quot;&gt;It offers a &lt;strong&gt;more concise and readable structured&lt;/strong&gt; manner compared to manual testing, making test cases easier to write and understand.&lt;/li&gt; 
&lt;li style=&quot;text-align: justify; margin: 1;&quot;&gt;The unittest module offers &lt;strong&gt;simplicity and compatibility&lt;/strong&gt;, especially with smaller projects or projects having strict and limited environments.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 style=&quot;margin: 0.5;&quot;&gt;Getting Started with Writing Test Cases&lt;/h2&gt; 
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;Let's understand the writing and execution of a test case using the unittest module of Python with an example:&lt;/p&gt; 
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;1. Setting up a Test Case&lt;/h3&gt; 
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;Suppose we create a class called employee, having all employee details. Now, we want to test the email pattern and payment increment method of each employee; for that, we need to write the test methods for checking emails as well as for payment of each employee. Let's start by writing the source code:&lt;/p&gt; 
&lt;pre&gt;&lt;code&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;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;First, create a directory for your project and navigate to it. Then create the new file with the name, test_employee.py. So, your directory structure will look something like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://logiclair.org/?qa=blob&amp;amp;qa_blobid=12342091770593375936&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;Then, &lt;strong&gt;import the unittest library&lt;/strong&gt; into the test_employee.py file. Also, import the Employee class from the src directory, where the source code of emplyess.py is provided.&lt;/p&gt; 
&lt;pre&gt;&lt;code&gt;import unittest #importing the module
from src_code.employee import Employee
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;2. Anatomy of a Test Case Class&lt;/h3&gt;  
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;After that, declare the test class derived from the base class of the unittest module. Then, define the test fixture methods i.e. &lt;strong&gt;setup() and teardown() methods&lt;/strong&gt; containing the code required before and after the execution of test methods.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;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 tearDown(self): #deleting the employee 
        del self.emp1 
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;3. Writing Test Methods&lt;/h3&gt; 
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;Naming Conventions&lt;/h3&gt;  
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;The Python unittest module defines the naming convention to start the method name with the &lt;strong&gt;prefix test_&lt;/strong&gt; so that the unittest module can easily identify the test methods upon execution.&lt;/p&gt;
&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 give meaningful names to the testing methods that describe the method behavior for clarity.  
&lt;/span&gt; 
&lt;/div&gt;
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;Test Method Structure&lt;/h3&gt;  
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;The structure of the test method consists of AAA (Arrange, Act, and Assert). In arrange, you provide the setup values which we have done in the setup() function. The act includes the input and output values and invokes the function. Therefore, writing the test methods consists of the &lt;strong&gt;input values, the output values, and the assert condition&lt;/strong&gt; to verify the outcome.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def test_email(self):  #function names start from test_ prefix
    self.assertEqual(self.emp1.email, '*Emails are not allowed*')  #checks email of employee 1
    self.assertEqual(self.emp2.email, '*Emails are not allowed*')  #check email of employee 2
    
def test_increment(self): #function names start from test_ prefix
    self.emp1.increment()  #call the increment function
    self.emp2.increment() 
    self.assertEqual(self.emp1.pay, 52500) #verfiy the increment value
    self.assertEqual(self.emp2.pay, 63000)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;4. Running the Test Case&lt;/h3&gt; 
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;For running the test case, the &lt;strong&gt;test runner function&lt;/strong&gt; is used at the end of the test_employee.py file.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;Output&lt;/strong&gt;&lt;br&gt;
&lt;img src=&quot;https://logiclair.org/?qa=blob&amp;amp;qa_blobid=2178352971083264680&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 style=&quot;margin: 0.5;&quot;&gt;Organizing Test Cases&lt;/h2&gt;
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;Test case management and organization play a crucial role in streamlining the testing process, enhancing productivity, and ensuring comprehensive test coverage. Well-structured test cases will help the QA team to test the &lt;strong&gt;specific functionality easily&lt;/strong&gt;, track the record of test case results, and &lt;strong&gt;figure out the bugs&lt;/strong&gt; promptly. If the test cases are unorganized, then it creates chaos between the team members, leading to inefficient and duplicate efforts.&lt;/p&gt;
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;1. Grouping Test Cases into Test Suites&lt;/h3&gt; 
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;In software testing, the test suite is the &lt;strong&gt;collection of test cases&lt;/strong&gt; that belong to the same category such as functionalities, scenarios, and features. Each test suite &lt;strong&gt;works for a specific aspect&lt;/strong&gt;. This will help the tester to categorize similar features and execute the multiple test cases parallel effectively.&lt;/p&gt; 
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;2. Using test loaders to discover and load test cases&lt;/h3&gt; 
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;Test loader is one of the functions of the unittest module, used for &lt;strong&gt;dynamically loading the test cases&lt;/strong&gt; from the test suite. An automated process of &lt;strong&gt;locating and executing&lt;/strong&gt; the test cases reduces the need for manual intervention and the risk of human errors. You can use the &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.python.org/3/library/unittest.html#unittest.TestLoader&quot; title=&quot;file&quot;&gt;unittest.TestLoader()&lt;/a&gt; function, to discover the test case.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import unittest #importing the module
from src_code.employee import Employee

class email_testing(unittest.TestCase): #testcase 1: for testing the email
    def test_email(self):
        self.emp1 = Employee('john', 50000)
        self.emp2 = Employee('stephen', 60000)
        self.assertEqual(self.emp1.email, '*Emails are not allowed*')
        self.assertEqual(self.emp2.email, '*Emails are not allowed*')

class increment_testing(unittest.TestCase): #testcase 2: for testing the payement increment
    def test_increment(self):
        self.emp1 = Employee('john', 50000)
        self.emp2 = Employee('stephen', 60000)
        self.emp1.increment()
        self.emp2.increment()
        self.assertEqual(self.emp1.pay, 52500)
        self.assertEqual(self.emp2.pay, 63000)

def create_test_suite(): #create suite 
    suite = unittest.TestSuite()
    suite.addTest(unittest.makeSuite(email_testing)) #add email testing testcase in the suite
    suite.addTest(unittest.makeSuite(increment_testing)) #add payment testing testcase in the suite
    return suite
        
if __name__ == '__main__': #used to class the main class of unittest
    loader = unittest.TestLoader()#deriving the loader from unittest module
    suite = create_test_suite()
    unittest.TextTestRunner().run(suite)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Output&lt;/strong&gt;&lt;br&gt;
&lt;img src=&quot;https://logiclair.org/?qa=blob&amp;amp;qa_blobid=14951185892787879650&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;3. Organizing Test Suites and Test Cases Using Modules and Classes&lt;/h3&gt;
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;Organizing the test suite and test cases using modules and classes provides the &lt;strong&gt;structures and granular approach&lt;/strong&gt; for testing the application. The &lt;strong&gt;modules define the test cases&lt;/strong&gt;, which means each module has &lt;strong&gt;specific functionality&lt;/strong&gt;. Whereas, the &lt;strong&gt;classes define the test suite&lt;/strong&gt;, which contains the &lt;strong&gt;group of test cases&lt;/strong&gt; having similar features and scenarios. This approach will help the developer enhance the readability of the code, and promote the reusability of the modules.&lt;/p&gt;
&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;Try to follow a test-driven development approach, this will prepare you to write test cases before the actual development.
&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: How can I run a test file using the command prompt? &lt;br&gt;A: You can easily run the file in CMD by using this command &quot;python -m unittest test_file.py&quot;.&lt;/span&gt;
&lt;span class=&quot;faq-body&quot; style=&quot;margin-top: 1px; margin-bottom: 5px;&quot;&gt; Q: If I dont use the prefix &quot;test_&quot; my method consider as test method? &lt;br&gt;A: No, the unittest module doesn't take the method as a testing method if the naming convention is not followed properly.&lt;/span&gt;
&lt;span class=&quot;faq-body&quot; style=&quot;margin-top: 1px; margin-bottom: 5px;&quot;&gt; Q: What is test coverage? &lt;br&gt;A: Test coverage is the technique that tells us how much application features and code are covered by test cases.&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;In conclusion, we learned that test cases are the &lt;strong&gt;essential building blocks of software testing&lt;/strong&gt;. Most developers use test cases to verify the software application's robustness, &lt;strong&gt;system maintenance&lt;/strong&gt;, and specific features based on the requirements given by the user. Additionally, it helps you &lt;strong&gt;evaluate the quality&lt;/strong&gt; and reliability of your application. Whether you are working on an enterprise-level application or developing a small program, testing is important to ensure &lt;strong&gt;every feature works properly&lt;/strong&gt;, even if it's a hectic process. However, all this becomes easy with the help of Python's built-in testing framework i.e. unittest. So, stay with me for the details of this module. I hope this guide is helpful for you. Happy Coding!&lt;/p&gt;
&lt;hr&gt;
&lt;h2 style=&quot;margin: 0.5;&quot;&gt; Reference&lt;/h2&gt;   
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.python.org/3/library/unittest.html&quot; title=&quot;file&quot;&gt;unittest Module&lt;/a&gt; &lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.python.org/3/library/unittest.html#unittest.TestCase&quot; title=&quot;file&quot;&gt;Test Case&lt;/a&gt;&lt;/p&gt;
</description>
<category>Testing</category>
<guid isPermaLink="true">https://coderlegion.com/215/testing-in-python-writing-test-cases-with-unittest</guid>
<pubDate>Mon, 08 Apr 2024 21:17:24 +0000</pubDate>
</item>
</channel>
</rss>