How to Write Test Cases for Search Functionality (With Examples)

How to Write Test Cases for Search Functionality (With Examples)

April 20, 2026 · 16 min read · How-To Guides

How to Write Test Cases for Search Functionality (With Examples)

Search is one of the most used features in any application, yet it is also one of the most fault‑prone. A single missed edge case can lead to irrelevant results, security holes, or a frustrating user experience that drives users away. This guide walks you through a complete process for creating high‑signal test cases for search functionality, from anatomy to prioritization, manual and automated execution, and finally a practical checklist you can bookmark. Throughout the article you will find a worked test matrix with more than twenty examples, code snippets that show how to automate the checks, and notes on how autonomous exploration tools like SUSA can supplement manual effort.

How to Write Test Cases for Search Functionality (With Examples): Test Case Anatomy

Every test case needs a clear structure so that reviewers, developers, and automation engineers can understand it at a glance. The following elements are essential:

Elements of a Test Case

A well‑written test case avoids vague language. Instead of “enter something in the search box”, write “type the string red shoes into the search input field with the placeholder Search products…”. This eliminates interpretation differences between manual testers and automated scripts. When you write the expected result, be explicit about both the data and the UI state. For example, “the results pane displays exactly three product cards, each containing the title Red Running Shoes, price $49.99, and an Add to Cart button that is enabled”.

Writing Clear Steps and Expected Results

Steps should follow the given‑when‑then pattern implicitly:

  1. Given – preconditions and test data are satisfied.
  2. When – the user performs the action (e.g., clicks the search button).
  3. Then – the system exhibits the expected behavior.

Avoid combining multiple actions in a single step; splitting them makes debugging easier when a step fails. For expected results, include both positive assertions (what should appear) and negative assertions (what should not appear). For a negative test case you might state, “no results are shown and an inline message No products match your query is displayed”.

How to Write Test Cases for Search Functionality (With Examples): Positive Test Cases

Positive test cases verify that the search engine returns the correct results for valid input. Below is a representative set organized by theme. Each row can be copied directly into a test management tool.

Basic Valid Queries

IDPreconditionsStepsExpected Result
S01Product index contains items: “Apple iPhone 12”, “Samsung Galaxy S21”, “Google Pixel 5”. No active filters.1. Tap the search bar. 2. Enter iPhone. 3. Press the search icon.Results list shows only the Apple iPhone 12 card. No other items appear.
S02Same index as S01.1. Tap search bar. 2. Enter galaxy s. 3. Press search.Results list shows only the Samsung Galaxy S21 card.
S03Index includes a product with SKU ABC-123.1. Tap search bar. 2. Enter ABC-123. 3. Press search.Exactly one result with SKU ABC-123 is displayed.
S04Index contains 1000 products; none match the query zzz.1. Enter zzz. 2. Press search.No results pane shows the message No products match your query.
S05Index contains products with prices ranging from $5 to $500.1. Enter under 100. 2. Press search.Results list includes only products whose price ≤ $100, sorted by relevance.

Synonyms and Stemming

IDPreconditionsStepsExpected Result
S06Index contains “running shoes”, “jogging sneakers”, “athletic footwear”. Synonym map: run ↔ jog. Stemming enabled for -ing.1. Enter jog. 2. Press search.Results include “running shoes”, “jogging sneakers”, “athletic footwear”.
S07Same index.1. Enter runs. 2. Press search.Results include “running shoes” (stemmed to run).
S08Index contains “cat”, “cats”, “caterpillar”.1. Enter cat. 2. Press search.Results include “cat” and “cats” but not “caterpillar” (if tokenization respects word boundaries).
S09Index contains “color” (US) and “colour” (UK). Synonym map includes both spellings.1. Enter colour. 2. Press search.Results include both US and UK spelling variants.
S10Index contains “e‑mail” and “email”.1. Enter email. 2. Press search.Results include both hyphenated and non‑hyphenated forms.

Filters and Sorting

IDPreconditionsStepsExpected Result
S11Index includes products with attributes: category (Electronics, Books), brand (Sony, Apple), price.1. Enter headphones. 2. Open filter panel. 3. Select category Electronics. 4. Apply.Results list shows only headphones tagged as Electronics.
S12Same as S11.1. After applying category filter, select brand Sony. 2. Apply.Results list shows only Sony headphones.
S13Index contains 50 products priced between $10 and $200.1. Enter speaker. 2. Open sort dropdown. 3. Choose Price: Low to High. 4. Apply.Results are displayed in ascending price order; first item ≤ $20, last item ≥ $180.
S14Same as S13.1. Choose Price: High to Low. 2. Apply.Results are displayed in descending price order.
S15Index includes timestamped blog posts.1. Enter AI. 2. Open date filter. 3. Select Last 30 days. 4. Apply.Only posts published within the last 30 days containing AI appear.
S16Index contains documents with language tags (en, es, fr).1. Enter manual. 2. Open language filter. 3. Select es. 4. Apply.Only Spanish language documents are shown.

How to Write Test Cases for Search Functionality (With Examples): Negative and Edge Cases

Negative tests confirm that the system handles invalid or unexpected input gracefully. Edge cases push the limits of length, character sets, and concurrency.

Empty and Whitespace Queries

IDPreconditionsStepsExpected Result
N01Index populated. Search bar empty.1. Tap search icon without typing.Inline validation shows Please enter a search term. No results request is sent to backend.
N02Same.1. Enter a single space ( ). 2. Tap search.Same validation as N01 (or trimmed to empty and shows same message).
N03Same.1. Enter three spaces ( ). 2. Tap search.Validation error appears; no network call.
N04Same.1. Enter a tab character (\t). 2. Tap search.Treated as whitespace; validation error appears.
N05Same.1. Enter a newline (\n). 2. Tap search.Validation error appears.

Special Characters and SQL Injection

IDPreconditionsStepsExpected Result
N06Index contains product O'Reilly.1. Enter O'Reilly. 2. Tap search.Results show the product; no error or unexpected behavior.
N07Same.1. Enter '; DROP TABLE products;--. 2. Tap search.System treats the string as literal search term; returns zero results (or appropriate no‑match message). No database error is exposed.
N08Same.1. Enter . 2. Tap search.Input is escaped or stripped; no script executes in the results page.
N09Same.1. Enter %%%. 2. Tap search.System returns zero results or a message indicating no matches; no crash.
N10Same.1. Enter a string of 1000 ampersands (&&&&…). 2. Tap search.System handles the input without throwing an exception; response time stays within SLA.

Very Long Queries

IDPreconditionsStepsExpected Result
L01Index contains typical product names (max length 100 chars).1. Generate a random string of 2000 characters. 2. Paste into search bar. 3. Tap search.Backend returns a 400 Bad Request or a UI message Search term too long (max 100 characters). No crash.
L02Same.1. Enter exactly 100 characters (the limit). 2. Tap search.Query is accepted and processed; results returned according to relevance.
L03Same.1. Enter 101 characters. 2. Tap search.Validation error appears; no backend call.
L04Same.1. Enter a string of 5000 Unicode emojis. 2. Tap search.Same length validation error as L01/L03.
L05Same.1. Enter a mix of 80 Latin characters and 20 CJK characters. 2. Tap search.Query accepted if total code units ≤ limit; results returned.

Unicode and Emoji

IDPreconditionsStepsExpected Result
U01Index contains product named 😀 Smiling Face T‑Shirt.1. Enter 😀. 2. Tap search.Result shows the T‑Shirt.
U02Same.1. Enter smiling face. 2. Tap search.Result shows the T‑Shirt (if synonym/emoji mapping enabled).
U03Index contains product café.1. Enter cafe (without accent). 2. Tap search.Depending on normalization, either returns the café product (if accent‑insensitive) or shows no match (if accent‑sensitive). Document the behavior.
U04Same.1. Enter é. 2. Tap search.Returns café if diacritic‑sensitive matching is enabled.
U05Index contains product 👍 Thumbs Up Sticker.1. Enter 👍. 2. Tap search.Returns the sticker.
U06Same.1. Enter thumbs up. 2. Tap search.Returns the sticker if mapping configured; otherwise no match.
U07Index contains product with Japanese title こんにちは.1. Enter こんにちは. 2. Tap search.Returns the product.
U08Same.1. Enter konnichiwa (romaji). 2. Tap search.Behavior depends on transliteration support; document outcome.

Data Setup and Test Environment for Search Testing

Reliable test execution depends on a known, repeatable state of the search index and any external services it relies on (e.g., recommendation engines, personalization APIs). The following practices help you create a stable foundation.

Populating Test Index

Before each test suite run, reset the index to a baseline dataset. Use scripts that:

  1. Delete the existing index (or collection).
  2. Load a CSV or JSON fixture containing a controlled set of records with known fields (title, description, price, categories, timestamps, language tags).
  3. Optionally inject specific edge‑case records (e.g., very long titles, special characters, emojis).
  4. Commit the index and verify document count matches the fixture.

A sample Bash snippet using Elasticsearch’s _bulk API:


#!/usr/bin/env bash
INDEX="test_search"
curl -X DELETE "http://localhost:9200/$INDEX?pretty"
curl -X PUT "http://localhost:9200/$INDEX" -H 'Content-Type: application/json' -d'
{
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 0,
    "analysis": {
      "analyzer": {
        "default": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": ["lowercase", "asciifolding"]
        }
      }
    }
  }
}'
# Load fixtures
curl -X POST "http://localhost:9200/$INDEX/_bulk?pretty" -H 'Content-Type: application/json' --data-binary @fixtures.json

Mocking External Services

If your search ranking depends on a recommendation microservice or a real‑time personalization engine, replace those calls with deterministic stubs during testing. Tools like WireMock (Java) or msw (JavaScript) let you define fixed responses:


// msw handler for personalization endpoint
import { rest } from 'msw'
export const handlers = [
  rest.get('/api/personalization/:userId', (req, res, ctx) => {
    return res(
      ctx.json({ boostFactor: 1.0, excludedCategories: [] })
    )
  })
]

Using SUSA for Autonomous Exploration (mention SUSA here)

SUSA can be pointed at a running build of your application to exercise search without writing scripts. After you upload the APK or provide the web URL, SUSA’s autonomous agent will:

You can invoke SUSA from CI with:


pip install susatest-agent
susatest run --app ./app-debug.apk --personas all --output susa-report.json

The report feeds into your test case prioritization: any flow that SUSA flags as flaky or error‑prone becomes a candidate for additional manual or automated test cases.

Prioritization and Traceability to Requirements

Not all test cases carry equal weight. Use a risk‑based matrix that combines likelihood of failure with impact on users. Link each test case to a specific requirement or user story so that coverage gaps are visible.

Risk‑Based Prioritization

Define two scales:

Calculate a priority score (e.g., Likelihood × Impact) and sort. Example mapping:

Likelihood \ ImpactLowMediumHighCritical
RareL1L2L3L4
UnlikelyL2L3L4L5
PossibleL3L4L5L6
LikelyL4L5L6L7
CertainL5L6L7L8

Assign numeric values (1‑8) and treat ≤ 3 as Low, 4‑5 as Medium, 6‑7 as High, ≥ 8 as Critical for execution order.

Linking Test Cases to User Stories

In your test management tool (e.g., Jira, TestRail, Zephyr), add a field “Related Requirement” that stores the issue key of the user story. For search, typical stories might be:

When you create a test case, copy the story ID into the “Related Requirement” field. This enables traceability reports that show, for each story, the percentage of test cases that are automated, passed, or pending.

Manual vs Automated Approaches for Search Test Cases

Both manual exploratory testing and automated regression suites have roles. The decision matrix below helps you decide where to invest effort.

FactorManual TestingAutomated Testing
Exploratory valueHigh – testers can try unexpected queries, observe UI subtleties.Low – follows pre‑defined scripts.
Regression safetyMedium – depends on tester diligence.High – runs on every build, catches regressions fast.
Setup timeLow – just a device or browser.Medium – requires test framework, data seeding, CI integration.
MaintenanceLow – no code to maintain.Medium – scripts need updates when locators or APIs change.
Performance/LoadLimited – manual repetition is tedious.Easy to scale with tools like JMeter or k6.
Accessibility checksPossible with screen‑reader testing, but inconsistent.Automated axe‑core or similar can be integrated.

When to Automate

Automate test cases that:

Leave to manual testing:

Sample Automated Script (Appium + Playwright)

Below is a compact example that verifies a positive search scenario on an Android app using Appium, then the same scenario on a web version using Playwright. Adjust capabilities and selectors to match your product.

#### Appium (Android) – Java


import io.appium.java_client.AppiumDriver;
import io.appium.java_client.MobileElement;
import io.appium.java_client.android.AndroidDriver;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.remote.DesiredCapabilities;

import java.net.URL;
import java.util.List;

public class SearchTest {
    private AppiumDriver<MobileElement> driver;

    @Before
    public void setUp() throws Exception {
        DesiredCapabilities caps = new DesiredCapabilities();
        caps.setCapability("deviceName", "Pixel_4_API_33");
        caps.setCapability("platformName", "Android");
        caps.setCapability("appPackage", "com.example.shop");
        caps.setCapability("appActivity", ".MainActivity");
        caps.setCapability("automationName", "UiAutomator2");
        driver = new AndroidDriver<>(new URL("http://localhost:4723/wd/hub"), caps);
    }

    @Test
    public void testBasicQuery() {
        MobileElement searchBox = driver.findElement(By.id("com.example.shop:id/search_src_text"));
        searchBox.sendKeys("iPhone");
        driver.findElement(By.id("com.example.shop:id/search_button")).click();

        // Wait for results
        List<MobileElement> results = driver.findElements(By.id("com.example.shop:id/product_title"));
        assert results.size() == 1;
        assert results.get(0).getText().equals("Apple iPhone 12");
    }

    @After
    public void tearDown() {
        if (driver != null) driver.quit();
    }
}

#### Playwright (Web) – TypeScript


import { test, expect } from '@playwright/test';

test.describe('Search functionality', () => {
  test('returns correct product for query', async ({ page }) => {
    await page.goto('https://shop.example.com');
    await page.fill('input[placeholder="Search products…"]', 'iPhone');
    await page.press('input[placeholder="Search products…"]', 'Enter');

    const results = page.locator('.product-card');
    await expect(results).toHaveCount(1);
    await expect(results.first()).toContainText('Apple iPhone 12');
    await expect(results.first()).toContainText('$49.99');
  });

  test('shows validation error on empty input', async ({ page }) => {
    await page.goto('https://shop.example.com');
    await page.press('input[placeholder="Search products…"]', 'Enter');
    const error = page.locator('.search-error');
    await expect(error).toBeVisible();
    await expect(error).toHaveText('Please enter a search term');
  });
});

These snippets illustrate how you can keep the same logical steps (fill, submit, assert) across platforms while leveraging each framework’s strengths.

Maintaining Test Suites

Real‑World Production Edge Cases That Slip Through

Even with exhaustive test matrices, certain issues only manifest under real‑world traffic patterns or after configuration changes. Below are several categories that have historically escaped pre‑release testing.

Faceted Navigation Drift

When product attributes are updated (e.g., a new color facet is added), the search UI may still show stale facet counts or allow selection of defunct options. This leads to zero‑result pages despite valid queries. Detect by:

Personalization and A/B Tests

If your search ranking incorporates a personalization service that buckets users into variants, a test account may fall into a variant that uses a different ranking model, causing expected result order to differ. Mitigation strategies:

Locale‑Specific Tokenization

Search analyzers often differ by locale (e.g., Japanese uses MeCab, German uses stemming rules). A test suite that runs only with en_US may miss tokenization bugs for ja_JP or de_DE. To catch these:

Index Replication Lag

In distributed search clusters, writes may take seconds to propagate to all replicas. A test that immediately queries after a data‑load step can see stale results. Solutions:

Query‑Time Boosting Experiments

Product teams often run short‑lived boost experiments (e.g., “increase score of items on sale”). If the experiment is active during a test run, the result order may shift unexpectedly. Countermeasures:

Checklist for Writing High‑Signal Search Test Cases

Use this checklist before you mark a test case as ready for execution. Each item can be copied into a markdown task list.

How to Write Test Cases for Search Functionality (With Examples): Closing Takeaways

Writing effective test cases for search is not a one‑time activity; it is a continuous loop of design, execution, analysis, and refinement. By starting with a solid anatomy, covering positive, negative, and edge‑case scenarios, anchoring each case to requirements, and balancing manual exploration with automated regression, you achieve coverage that catches both obvious defects and the subtle, production‑only issues that erode trust. Remember to:

Apply these practices, and you will transform search from a frequent source of user frustration into a reliable, high‑performing gateway to your application’s content. Happy testing!

Test Your App Autonomously

Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts.

Try SUSA Free