test_queries.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. """
  2. 向量搜索查询单元测试
  3. 测试向量搜索应用层的查询定义和验证逻辑。
  4. """
  5. import pytest
  6. from src.application.vector_search.queries import (
  7. SearchDocumentsQuery,
  8. GetDocumentQuery,
  9. )
  10. class TestSearchDocumentsQuery:
  11. """SearchDocumentsQuery 单元测试"""
  12. def test_create_with_valid_query_text(self):
  13. """测试使用有效查询文本创建查询"""
  14. # Act
  15. query = SearchDocumentsQuery(query_text="machine learning")
  16. # Assert
  17. assert query.query_text == "machine learning"
  18. assert query.top_k == 10
  19. assert query.filters is None
  20. assert query.use_hybrid is True
  21. assert query.min_score is None
  22. def test_create_with_custom_top_k(self):
  23. """测试使用自定义 top_k 创建查询"""
  24. # Act
  25. query = SearchDocumentsQuery(
  26. query_text="deep learning",
  27. top_k=20
  28. )
  29. # Assert
  30. assert query.query_text == "deep learning"
  31. assert query.top_k == 20
  32. def test_create_with_filters(self):
  33. """测试使用过滤条件创建查询"""
  34. # Act
  35. query = SearchDocumentsQuery(
  36. query_text="neural networks",
  37. filters={"category": "AI", "language": "en"}
  38. )
  39. # Assert
  40. assert query.query_text == "neural networks"
  41. assert query.filters == {"category": "AI", "language": "en"}
  42. def test_create_with_use_hybrid_false(self):
  43. """测试使用 use_hybrid=False 创建查询"""
  44. # Act
  45. query = SearchDocumentsQuery(
  46. query_text="test query",
  47. use_hybrid=False
  48. )
  49. # Assert
  50. assert query.use_hybrid is False
  51. def test_create_with_min_score(self):
  52. """测试使用最小分数阈值创建查询"""
  53. # Act
  54. query = SearchDocumentsQuery(
  55. query_text="test query",
  56. min_score=0.7
  57. )
  58. # Assert
  59. assert query.min_score == 0.7
  60. def test_create_with_empty_query_text_raises_error(self):
  61. """测试使用空查询文本创建查询会抛出错误"""
  62. # Act & Assert
  63. with pytest.raises(ValueError, match="Search query text cannot be empty"):
  64. SearchDocumentsQuery(query_text="")
  65. def test_create_with_whitespace_only_query_text_raises_error(self):
  66. """测试使用仅空白字符的查询文本创建查询会抛出错误"""
  67. # Act & Assert
  68. with pytest.raises(ValueError, match="Search query text cannot be whitespace only"):
  69. SearchDocumentsQuery(query_text=" \n\t ")
  70. def test_create_with_non_string_query_text_raises_error(self):
  71. """测试使用非字符串查询文本创建查询会抛出错误"""
  72. # Act & Assert
  73. with pytest.raises(ValueError, match="Search query text must be a string"):
  74. SearchDocumentsQuery(query_text=123) # type: ignore
  75. def test_create_with_zero_top_k_raises_error(self):
  76. """测试使用 top_k=0 创建查询会抛出错误"""
  77. # Act & Assert
  78. with pytest.raises(ValueError, match="top_k must be positive"):
  79. SearchDocumentsQuery(
  80. query_text="test query",
  81. top_k=0
  82. )
  83. def test_create_with_negative_top_k_raises_error(self):
  84. """测试使用负数 top_k 创建查询会抛出错误"""
  85. # Act & Assert
  86. with pytest.raises(ValueError, match="top_k must be positive"):
  87. SearchDocumentsQuery(
  88. query_text="test query",
  89. top_k=-5
  90. )
  91. def test_create_with_top_k_exceeding_limit_raises_error(self):
  92. """测试使用超过限制的 top_k 创建查询会抛出错误"""
  93. # Act & Assert
  94. with pytest.raises(ValueError, match="top_k cannot exceed 1000"):
  95. SearchDocumentsQuery(
  96. query_text="test query",
  97. top_k=1001
  98. )
  99. def test_create_with_non_integer_top_k_raises_error(self):
  100. """测试使用非整数 top_k 创建查询会抛出错误"""
  101. # Act & Assert
  102. with pytest.raises(ValueError, match="top_k must be an integer"):
  103. SearchDocumentsQuery(
  104. query_text="test query",
  105. top_k=10.5 # type: ignore
  106. )
  107. def test_create_with_non_dict_filters_raises_error(self):
  108. """测试使用非字典过滤条件创建查询会抛出错误"""
  109. # Act & Assert
  110. with pytest.raises(ValueError, match="filters must be a dictionary or None"):
  111. SearchDocumentsQuery(
  112. query_text="test query",
  113. filters="invalid" # type: ignore
  114. )
  115. def test_create_with_non_boolean_use_hybrid_raises_error(self):
  116. """测试使用非布尔值 use_hybrid 创建查询会抛出错误"""
  117. # Act & Assert
  118. with pytest.raises(ValueError, match="use_hybrid must be a boolean"):
  119. SearchDocumentsQuery(
  120. query_text="test query",
  121. use_hybrid="yes" # type: ignore
  122. )
  123. def test_create_with_min_score_below_zero_raises_error(self):
  124. """测试使用小于 0 的 min_score 创建查询会抛出错误"""
  125. # Act & Assert
  126. with pytest.raises(ValueError, match="min_score must be between 0.0 and 1.0"):
  127. SearchDocumentsQuery(
  128. query_text="test query",
  129. min_score=-0.1
  130. )
  131. def test_create_with_min_score_above_one_raises_error(self):
  132. """测试使用大于 1 的 min_score 创建查询会抛出错误"""
  133. # Act & Assert
  134. with pytest.raises(ValueError, match="min_score must be between 0.0 and 1.0"):
  135. SearchDocumentsQuery(
  136. query_text="test query",
  137. min_score=1.5
  138. )
  139. def test_create_with_non_numeric_min_score_raises_error(self):
  140. """测试使用非数值 min_score 创建查询会抛出错误"""
  141. # Act & Assert
  142. with pytest.raises(ValueError, match="min_score must be a number or None"):
  143. SearchDocumentsQuery(
  144. query_text="test query",
  145. min_score="0.7" # type: ignore
  146. )
  147. def test_has_filters_returns_true_when_filters_provided(self):
  148. """测试当提供过滤条件时 has_filters 返回 True"""
  149. # Arrange
  150. query = SearchDocumentsQuery(
  151. query_text="test query",
  152. filters={"category": "AI"}
  153. )
  154. # Act & Assert
  155. assert query.has_filters() is True
  156. def test_has_filters_returns_false_when_filters_not_provided(self):
  157. """测试当不提供过滤条件时 has_filters 返回 False"""
  158. # Arrange
  159. query = SearchDocumentsQuery(query_text="test query")
  160. # Act & Assert
  161. assert query.has_filters() is False
  162. def test_has_filters_returns_false_when_filters_empty(self):
  163. """测试当过滤条件为空字典时 has_filters 返回 False"""
  164. # Arrange
  165. query = SearchDocumentsQuery(
  166. query_text="test query",
  167. filters={}
  168. )
  169. # Act & Assert
  170. assert query.has_filters() is False
  171. def test_has_min_score_returns_true_when_min_score_provided(self):
  172. """测试当提供最小分数时 has_min_score 返回 True"""
  173. # Arrange
  174. query = SearchDocumentsQuery(
  175. query_text="test query",
  176. min_score=0.7
  177. )
  178. # Act & Assert
  179. assert query.has_min_score() is True
  180. def test_has_min_score_returns_false_when_min_score_not_provided(self):
  181. """测试当不提供最小分数时 has_min_score 返回 False"""
  182. # Arrange
  183. query = SearchDocumentsQuery(query_text="test query")
  184. # Act & Assert
  185. assert query.has_min_score() is False
  186. def test_get_filter_value_returns_value_when_key_exists(self):
  187. """测试当键存在时 get_filter_value 返回值"""
  188. # Arrange
  189. query = SearchDocumentsQuery(
  190. query_text="test query",
  191. filters={"category": "AI", "language": "en"}
  192. )
  193. # Act & Assert
  194. assert query.get_filter_value("category") == "AI"
  195. assert query.get_filter_value("language") == "en"
  196. def test_get_filter_value_returns_default_when_key_not_exists(self):
  197. """测试当键不存在时 get_filter_value 返回默认值"""
  198. # Arrange
  199. query = SearchDocumentsQuery(
  200. query_text="test query",
  201. filters={"category": "AI"}
  202. )
  203. # Act & Assert
  204. assert query.get_filter_value("language", "unknown") == "unknown"
  205. def test_get_filter_value_returns_default_when_filters_none(self):
  206. """测试当过滤条件为 None 时 get_filter_value 返回默认值"""
  207. # Arrange
  208. query = SearchDocumentsQuery(query_text="test query")
  209. # Act & Assert
  210. assert query.get_filter_value("category", "default") == "default"
  211. class TestGetDocumentQuery:
  212. """GetDocumentQuery 单元测试"""
  213. def test_create_with_valid_document_id(self):
  214. """测试使用有效文档 ID 创建查询"""
  215. # Act
  216. query = GetDocumentQuery(document_id="doc_123")
  217. # Assert
  218. assert query.document_id == "doc_123"
  219. assert query.include_embedding is False
  220. def test_create_with_include_embedding_true(self):
  221. """测试使用 include_embedding=True 创建查询"""
  222. # Act
  223. query = GetDocumentQuery(
  224. document_id="doc_123",
  225. include_embedding=True
  226. )
  227. # Assert
  228. assert query.document_id == "doc_123"
  229. assert query.include_embedding is True
  230. def test_create_with_empty_document_id_raises_error(self):
  231. """测试使用空文档 ID 创建查询会抛出错误"""
  232. # Act & Assert
  233. with pytest.raises(ValueError, match="Document ID cannot be empty"):
  234. GetDocumentQuery(document_id="")
  235. def test_create_with_non_string_document_id_raises_error(self):
  236. """测试使用非字符串文档 ID 创建查询会抛出错误"""
  237. # Act & Assert
  238. with pytest.raises(ValueError, match="Document ID must be a string"):
  239. GetDocumentQuery(document_id=123) # type: ignore
  240. def test_create_with_non_boolean_include_embedding_raises_error(self):
  241. """测试使用非布尔值 include_embedding 创建查询会抛出错误"""
  242. # Act & Assert
  243. with pytest.raises(ValueError, match="include_embedding must be a boolean"):
  244. GetDocumentQuery(
  245. document_id="doc_123",
  246. include_embedding="yes" # type: ignore
  247. )