Non-Functional Testing — Performance, Security, Usability and More

A feature that works correctly can still fail its users. Pages that take ten seconds to load, forms that are impossible to navigate with a keyboard, and applications that expose passwords in plain text are all functional — and all unacceptable. Non-functional testing evaluates the quality attributes that determine whether software is not just correct, but usable, secure, performant, and reliable under real-world conditions.

Major Non-Functional Testing Types

Non-functional testing covers a broad spectrum of quality attributes. While a QA engineer may not specialise in all of them, understanding each type is essential for building comprehensive test plans and identifying when a specialist is needed.

# Major non-functional testing types with goals and metrics

NON_FUNCTIONAL_TYPES = [
    {
        "type": "Performance Testing",
        "question": "How fast and stable is the system under expected and peak load?",
        "sub_types": [
            "Load testing — behaviour under expected user volume",
            "Stress testing — behaviour beyond maximum capacity",
            "Endurance testing — stability over extended time periods",
            "Spike testing — response to sudden traffic surges",
        ],
        "key_metrics": ["Response time (p50, p95, p99)", "Throughput (req/sec)", "Error rate"],
        "tools": "JMeter, k6, Gatling, Locust",
    },
    {
        "type": "Security Testing",
        "question": "Is the system protected against common attacks and data breaches?",
        "sub_types": [
            "Vulnerability scanning — automated detection of known weaknesses",
            "Penetration testing — simulated attacks by ethical hackers",
            "Authentication/authorisation testing — access control verification",
            "Data protection testing — encryption, masking, secure storage",
        ],
        "key_metrics": ["OWASP Top 10 compliance", "Open vulnerabilities count", "Time to patch"],
        "tools": "OWASP ZAP, Burp Suite, SonarQube, Snyk",
    },
    {
        "type": "Usability Testing",
        "question": "Can real users accomplish their goals efficiently and without frustration?",
        "sub_types": [
            "Task-based testing — users attempt specific workflows",
            "Heuristic evaluation — experts assess against design principles",
            "A/B testing — comparing two design variants for user preference",
        ],
        "key_metrics": ["Task completion rate", "Time on task", "Error rate", "Satisfaction score"],
        "tools": "UserTesting, Hotjar, manual observation sessions",
    },
    {
        "type": "Accessibility Testing (a11y)",
        "question": "Can users with disabilities use the application effectively?",
        "sub_types": [
            "Screen reader compatibility (NVDA, VoiceOver, JAWS)",
            "Keyboard-only navigation",
            "Colour contrast compliance (WCAG AA/AAA)",
            "ARIA attribute validation",
        ],
        "key_metrics": ["WCAG 2.1 conformance level", "Automated a11y violations count"],
        "tools": "axe DevTools, Lighthouse, WAVE, Pa11y",
    },
    {
        "type": "Compatibility Testing",
        "question": "Does the application work across different environments?",
        "sub_types": [
            "Cross-browser testing (Chrome, Firefox, Safari, Edge)",
            "Cross-device testing (desktop, tablet, mobile)",
            "OS compatibility (Windows, macOS, Linux, iOS, Android)",
            "Screen resolution and responsive design testing",
        ],
        "key_metrics": ["Defects per browser/device", "Layout breakpoints verified"],
        "tools": "BrowserStack, LambdaTest, Sauce Labs, Chrome DevTools",
    },
]

for nft in NON_FUNCTIONAL_TYPES:
    print(f"\n{'='*55}")
    print(f"  {nft['type']}")
    print(f"{'='*55}")
    print(f"  Question: {nft['question']}")
    print(f"  Metrics:  {', '.join(nft['key_metrics'])}")
    print(f"  Tools:    {nft['tools']}")
    print(f"  Sub-types:")
    for st in nft['sub_types']:
        print(f"    - {st}")
Note: Accessibility testing is both a quality practice and a legal requirement in many jurisdictions. The Americans with Disabilities Act (ADA) in the US, the Equality Act in the UK, and the European Accessibility Act all mandate that digital products be accessible to users with disabilities. Failing an accessibility audit does not just mean a poor user experience — it can result in lawsuits and regulatory fines. Treating accessibility testing as optional is both an ethical and business risk.
Tip: You do not need to be a specialist to start non-functional testing. Run Lighthouse in Chrome DevTools — it gives you instant performance, accessibility and SEO scores with actionable recommendations. Run OWASP ZAP in automated scan mode against your staging URL — it finds common security vulnerabilities in minutes. These lightweight checks catch obvious problems before a specialist performs a deeper audit.
Warning: Never run performance or security tests against production without explicit approval. Load testing can overwhelm production servers and cause outages for real users. Security scanning can trigger intrusion detection systems and cause account lockouts. Always use dedicated test environments for non-functional testing and coordinate with your DevOps team before running any tests that generate significant traffic or simulate attacks.

Common Mistakes

Mistake 1 — Assuming the development framework handles security automatically

❌ Wrong: “We use React and Django, so XSS and CSRF are handled by the framework. No security testing needed.”

✅ Correct: “Frameworks provide security defaults, but misconfiguration, custom code, and third-party dependencies can introduce vulnerabilities. Security testing verifies that the implementation is actually secure, not just that the framework offers protection.”

Mistake 2 — Testing performance only with a single user

❌ Wrong: “I loaded the page and it took 1.5 seconds — performance is fine.”

✅ Correct: “Performance testing must simulate realistic concurrent user loads. A page that loads in 1.5 seconds for one user might take 15 seconds under 1,000 concurrent users. Use tools like JMeter or k6 to generate load and measure response times at expected and peak traffic levels.”

🧠 Test Yourself

Which non-functional testing type verifies that users with disabilities can effectively use the application?