Testing Pyramid Application
Unit Testing Strategies
Core Principles
Isolation : Each test case should run independently, without relying on external environments
Single Responsibility : Each test verifies only one functionality
Fast Feedback : Unit tests should complete in milliseconds
Implementation Approach
// React component unit test example (Jest + React Testing Library)
import { render, screen } from ' @testing-library/react ' ;
import Button from ' ./Button ' ;
describe ( ' Button Component ' , () => {
it ( ' renders with default props ' , () => {
render (< Button >Click Me</ Button >);
expect (screen. getByText ( ' Click Me ' )). toBeInTheDocument ();
});
it ( ' handles click events ' , () => {
const handleClick = jest. fn ();
render (< Button onClick ={ handleClick } >Click Me</ Button >);
userEvent. click (screen. getByText ( ' Click Me ' ));
expect (handleClick). toHaveBeenCalledTimes ( 1 );
});
});
Best Practices
Target 70-80% coverage for critical logic
Use mocks to isolate external dependencies
Follow the AAA pattern (Arrange-Act-Assert)
Integration Testing Strategies
Test Scope
Component interactions
Inter-module communication
Data flow validation
Implementation Approach
// Micro frontend communication integration test example
import { eventBus } from ' ./eventBus ' ;
describe ( ' Microfrontend Communication ' , () => {
it ( ' should handle user login event ' , () => {
const mockHandler = jest. fn ();
eventBus. on ( ' user-login ' , mockHandler);
eventBus. emit ( ' user-login ' , { id : 1 , name : ' Test User ' });
expect (mockHandler). toHaveBeenCalledWith ({ id : 1 , name : ' Test User ' });
});
});
Challenges and Solutions
Cross-Application Dependencies : Use test doubles (stubs/mocks)
Environment Consistency : Use Docker for containerized test environments
Performance Considerations : Run test cases in parallel
End-to-End (E2E) Testing Strategies
Testing Pyramid Positioning
Base: Unit Tests (70%)
Middle: Integration Tests (20%)
Top: E2E Tests (10%)
Implementation Approach (Cypress Example)
// Micro frontend application E2E test
describe ( ' Microfrontend Application ' , () => {
beforeEach (() => {
cy. visit ( ' / ' );
});
it ( ' loads all microfrontends ' , () => {
cy. get ( ' [data-testid="app1"] ' ). should ( ' be.visible ' );
cy. get ( ' [data-testid="app2"] ' ). should ( ' be.visible ' );
});
it ( ' handles cross-app navigation ' , () => {
cy. get ( ' [data-testid="navigate-to-app2"] ' ). click ();
cy. url (). should ( ' include ' , ' /app2 ' );
cy. get ( ' [data-testid="app2-content"] ' ). should ( ' exist ' );
});
});
Key Considerations
Test Data Management : Use tools like Factory Boy to generate test data
Environment Isolation : Ensure independent environments for each test case
Execution Efficiency : Selectively run critical path E2E tests
Micro Frontend-Specific Testing
Application Isolation Testing
Testing Goals
Ensure sub-applications do not pollute the global namespace
Verify style isolation effectiveness
Confirm JavaScript sandbox functionality
Testing Approach
// Style isolation test example
describe ( ' Style Isolation ' , () => {
it ( ' should not leak styles to parent app ' , () => {
// Load sub-application
loadMicroApp ( ' app1 ' );
// Verify parent app styles are unaffected
expect (document.body.style.backgroundColor).not. toEqual ( ' red ' );
// Verify sub-app styles are confined to container
const appContainer = document. getElementById ( ' app1-container ' );
expect (appContainer. querySelector ( ' .child-style ' )). toHaveStyle ( ' color: blue ' );
});
});
Communication Mechanism Testing
Test Scenarios
Event bus communication
Custom protocol communication
Shared state synchronization
Implementation Example
// Event bus communication test
describe ( ' Event Bus Communication ' , () => {
it ( ' should propagate events between apps ' , ( done ) => {
// Sub-application listens for event
window. addEventListener ( ' custom-event ' , ( e ) => {
expect (e.detail). toEqual ({ data : ' test ' });
done ();
});
// Main application triggers event
window. dispatchEvent ( new CustomEvent ( ' custom-event ' , {
detail : { data : ' test ' }
}));
});
});
Loading Process Testing
Testing Key Points
Loading performance metrics
Error handling paths
Fallback mechanisms
Testing Approach
// Loading performance test
describe ( ' Microfrontend Loading Performance ' , () => {
it ( ' should load within performance budgets ' , async () => {
const start = performance. now ();
await loadMicroApp ( ' app1 ' );
const duration = performance. now () - start;
expect (duration). toBeLessThan ( 3000 ); // Complete loading within 3 seconds
});
it ( ' should show fallback when loading fails ' , async () => {
// Simulate loading failure
jest. spyOn (window, ' fetch ' ). mockRejectedValue ( new Error ( ' Failed to load ' ));
render (< MicroAppLoader name = " app1 " />);
expect (screen. getByText ( ' Loading failed ' )). toBeInTheDocument ();
});
});
Automated Testing Frameworks
Jest Configuration and Usage
Base Configuration (jest.config.js)
module . exports = {
preset : ' ts-jest ' ,
testEnvironment : ' jsdom ' ,
moduleNameMapper : {
' ^@/(.*)$ ' : ' <rootDir>/src/$1 ' ,
' \\ .(css|less|scss|sass)$ ' : ' identity-obj-proxy '
},
setupFilesAfterEnv : [ ' <rootDir>/jest.setup.js ' ],
transform : {
' ^.+ \\ .(js|jsx|ts|tsx)$ ' : ' babel-jest ' ,
},
collectCoverageFrom : [
' src/**/*.{js,jsx,ts,tsx} ' ,
' !src/**/*.d.ts ' ,
' !src/index.tsx ' ,
' !src/serviceWorker.ts '
],
};
Testing Library Integration
// jest.setup.js
import ' @testing-library/jest-dom ' ;
import { configure } from ' enzyme ' ;
import Adapter from ' enzyme-adapter-react-16 ' ;
configure ({ adapter : new Adapter () });
Cypress/E2E Testing
Project Initialization
npm install cypress -- save - dev
npx cypress open
Key Configuration (cypress.json)
{
" baseUrl " : " http://localhost:3000 " ,
" video " : false ,
" viewportWidth " : 1280 ,
" viewportHeight " : 720 ,
" defaultCommandTimeout " : 10000 ,
" requestTimeout " : 15000
}
Test Example
// cypress/integration/app_spec.js
describe ( ' Microfrontend App ' , () => {
beforeEach (() => {
cy. visit ( ' / ' );
});
it ( ' loads the app ' , () => {
cy. contains ( ' Welcome to Micro Frontend ' ). should ( ' be.visible ' );
});
it ( ' handles user login ' , () => {
cy. get ( ' [data-testid="login-btn"] ' ). click ();
cy. get ( ' [data-testid="username"] ' ). type ( ' testuser ' );
cy. get ( ' [data-testid="login-submit"] ' ). click ();
cy. url (). should ( ' include ' , ' /dashboard ' );
});
});
Playwright Application
Advantage Comparison
Feature Cypress Playwright Browser Support Chrome, Edge Chromium, Firefox, WebKit Parallel Execution Limited Native support Mobile Testing Not supported Supported Network Interception Limited Robust
Test Example
// playwright/test/app.spec.js
const { test, expect } = require ( ' @playwright/test ' );
test. describe ( ' Microfrontend App ' , () => {
test ( ' loads successfully ' , async ({ page }) => {
await page. goto ( ' / ' );
await expect (page. locator ( ' [data-testid="app-header"] ' )). toHaveText ( ' Micro Frontend ' );
});
test ( ' handles navigation ' , async ({ page }) => {
await page. goto ( ' / ' );
await page. click ( ' [data-testid="navigate-to-app2"] ' );
await expect (page). toHaveURL ( / \/app2 / );
});
});
Test Coverage and Quality
Coverage Metrics Setting
Metric Unit Tests Integration Tests E2E Tests Statement Coverage ≥80% ≥70% ≥50% Branch Coverage ≥70% ≥60% ≥40% Function Coverage ≥85% ≥75% – Line Coverage ≥80% ≥70% –
Dynamic Threshold Strategy
// Dynamically adjust thresholds based on project complexity
function getCoverageThresholds ( projectSize ) {
if (projectSize === ' small ' ) {
return { statements : 70 , branches : 60 , functions : 75 , lines : 70 };
} else if (projectSize === ' medium ' ) {
return { statements : 80 , branches : 70 , functions : 85 , lines : 80 };
} else {
return { statements : 90 , branches : 80 , functions : 90 , lines : 85 };
}
}
Test Quality Assessment
Quality Metrics System
Stability : Test pass rate fluctuation <5%
Reliability : False positive rate <10%
Maintainability : Test code complexity <1.5x main code
Value : Defect detection rate >70%
Visualization Dashboard Example
// Test quality dashboard data
const testQualityMetrics = {
stability : {
currentPassRate : 98.2 ,
historicalTrend : [ 98.5 , 98.3 , 98.7 , 98.1 , 98.4 ]
},
reliability : {
falsePositives : 8 ,
totalTests : 850
},
maintainability : {
complexityRatio : 1.3 ,
techDebt : 15 // Person-days
}
};
Continuous Integration Testing
CI/CD Integration Strategy
# GitHub Actions example
name: CI Pipeline
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs :
test :
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [14.x, 16 .x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix . node-version } }
uses: actions/setup-node@v2
with:
node-version: ${{ matrix . node-version } }
- name: Install dependencies
run: npm ci
- name: Run Unit Tests
run: npm test -- --coverage
- name: Run E2E Tests
run: npm run e2e
- name: Upload Coverage
uses: codecov/codecov-action@v1
Test Parallelization Strategy
// Jest parallel configuration
module . exports = {
maxWorkers : ' 50% ' , // Use 50% of CPU cores
testMatch : [ ' **/__tests__/**/*.js?(x) ' , ' **/?(*.)+(spec|test).js?(x) ' ],
watchPlugins : [
' jest-watch-typeahead/filename ' ,
' jest-watch-typeahead/testname '
],
// Test sharding
shard : {
total : 3 ,
current : 1
}
};
Test Result Analysis and Reporting
// Test report generation configuration
const { createReport } = require ( ' multiple-cucumber-html-reporter ' );
createReport ({
jsonDir : ' cypress/cucumber-json ' ,
reportPath : ' ./cypress/report/cucumber_report.html ' ,
metadata : {
browser : {
name : ' chrome ' ,
version : ' 91 '
},
device : ' Local test machine ' ,
platform : {
name : ' ubuntu ' ,
version : ' 20.04 '
}
}
});
Summary and Recommendations
Testing Strategy Selection :
Unit tests cover core business logic (70-80%)
Integration tests validate critical paths (20%)
E2E tests ensure end-to-end flows (10%)
Micro Frontend-Specific Considerations :
Add application isolation testing
Strengthen communication mechanism validation
Optimize loading process testing
Framework Selection Recommendations :
Unit Testing: Jest + Testing Library
Integration Testing: Cypress/Playwright
E2E Testing: Cypress (simple scenarios)/Playwright (complex scenarios)
Quality Assurance System :
Establish dynamic coverage thresholds
Implement test quality assessment metrics
Enhance CI/CD testing workflows
Continuous Improvement Directions :
Automate test data management
Containerize test environments
Explore AI-assisted test case generation
By building a comprehensive testing system, micro frontend architectures can significantly improve software quality, reduce maintenance costs, and provide robust support for continuous delivery. Start with foundational unit tests, gradually enhance testing at all levels, and ultimately form a comprehensive automated testing safety net.