Back to Repositories

Testing Search Synonym Functionality in Searchkick

This test suite validates synonym functionality in Searchkick, focusing on search term equivalence and text matching behaviors. It covers basic synonym matching, directional synonyms, case sensitivity, and dynamic synonym reloading capabilities.

Test Coverage Overview

The test suite provides comprehensive coverage of Searchkick’s synonym handling capabilities across various search scenarios.

  • Basic synonym matching for common terms (bleach, bandaids)
  • Multi-word synonym handling (USA/United States)
  • Directional synonym relationships
  • Case sensitivity testing
  • Dynamic synonym reloading functionality

Implementation Analysis

The testing approach uses Minitest framework with a systematic pattern of storing sample data and asserting search results.

Tests are structured using setup_speaker helper and utilize store_names and assert_search methods for consistent test patterns. The implementation includes conditional testing for different Elasticsearch versions and environment-specific configurations.

Technical Details

  • Testing Framework: Minitest
  • Search Engine: Elasticsearch
  • Configuration: Environment-based synonym file handling
  • Helper Methods: setup_speaker, store_names, assert_search
  • Version Compatibility: Elasticsearch 7.3+ for advanced features

Best Practices Demonstrated

The test suite exemplifies strong testing practices through systematic organization and thorough coverage.

  • Isolated test cases with clear naming
  • Comprehensive edge case handling
  • Version-specific feature testing
  • Environment-aware configuration
  • Proper cleanup in ensure blocks

ankane/searchkick

test/search_synonyms_test.rb

            
require_relative "test_helper"

class SearchSynonymsTest < Minitest::Test
  def setup
    super
    setup_speaker
  end

  def test_bleach
    store_names ["Clorox Bleach", "Kroger Bleach"]
    assert_search "clorox", ["Clorox Bleach", "Kroger Bleach"]
  end

  def test_burger_buns
    store_names ["Hamburger Buns"]
    assert_search "burger buns", ["Hamburger Buns"]
  end

  def test_bandaids
    store_names ["Band-Aid", "Kroger 12-Pack Bandages"]
    assert_search "bandaids", ["Band-Aid", "Kroger 12-Pack Bandages"]
  end

  def test_reverse
    store_names ["Hamburger"]
    assert_search "burger", ["Hamburger"]
  end

  def test_not_stemmed
    store_names ["Burger"]
    assert_search "hamburgers", []
    assert_search "hamburger", ["Burger"]
  end

  def test_word_start
    store_names ["Clorox Bleach", "Kroger Bleach"]
    assert_search "clorox", ["Clorox Bleach", "Kroger Bleach"], {match: :word_start}
  end

  def test_directional
    store_names ["Lightbulb", "Green Onions", "Led"]
    assert_search "led", ["Lightbulb", "Led"]
    assert_search "Lightbulb", ["Lightbulb"]
    assert_search "Halogen Lamp", ["Lightbulb"]
    assert_search "onions", ["Green Onions"]
  end

  def test_case
    store_names ["Uppercase"]
    assert_search "lowercase", ["Uppercase"]
  end

  def test_multiple_words
    store_names ["USA"]
    assert_search "United States of America", ["USA"]
    assert_search "usa", ["USA"]
    assert_search "United States", []
  end

  def test_multiple_words_expanded
    store_names ["United States of America"]
    assert_search "usa", ["United States of America"]
    assert_search "United States of America", ["United States of America"]
    assert_search "United States", ["United States of America"] # no synonyms used
  end

  def test_reload_synonyms
    if Searchkick.server_below?("7.3.0")
      error = assert_raises(Searchkick::Error) do
        Speaker.searchkick_index.reload_synonyms
      end
      assert_equal "Requires Elasticsearch 7.3+", error.message
    else
      Speaker.searchkick_index.reload_synonyms
    end
  end

  def test_reload_synonyms_better
    skip unless ENV["ES_PATH"] && !Searchkick.server_below?("7.3.0")

    write_synonyms("test,hello")

    with_options({search_synonyms: "synonyms.txt"}, Speaker) do
      store_names ["Hello", "Goodbye"]
      assert_search "test", ["Hello"]

      write_synonyms("test,goodbye")
      assert_search "test", ["Hello"]

      Speaker.searchkick_index.reload_synonyms
      assert_search "test", ["Goodbye"]
    end
  ensure
    Speaker.reindex
  end

  def write_synonyms(contents)
    File.write("#{ENV.fetch("ES_PATH")}/config/synonyms.txt", contents)
  end

  def default_model
    Speaker
  end
end