diff --git a/test/conftest.py b/test/conftest.py
index 8256d1274c172f9df44d9013da5b7edd5d82f7c7..6026dad1ac92a9abe3c85379237acd60734b2c8c 100644
--- a/test/conftest.py
+++ b/test/conftest.py
@@ -195,6 +195,64 @@ class RaftStatus:
     leader_id: int | None = None
 
 
+class CasRange:
+    key_min = dict(kind="unbounded", value=None)
+    key_max = dict(kind="unbounded", value=None)
+    repr_min = "unbounded"
+    repr_max = "unbounded"
+
+    @property
+    def key_min_packed(self) -> dict:
+        key = self.key_min.copy()
+        key["value"] = msgpack.packb([key["value"]])
+        return key
+
+    @property
+    def key_max_packed(self) -> dict:
+        key = self.key_max.copy()
+        key["value"] = msgpack.packb([key["value"]])
+        return key
+
+    def __repr__(self):
+        return f"CasRange({self.repr_min}, {self.repr_max})"
+
+    def __init__(self, gt=None, ge=None, lt=None, le=None, eq=None):
+        """
+        Creates a CasRange from the specified bounds.
+
+        To specify a range for exactly one key use only: `eq`.
+        Example: `CasRange(eq=1) # [1,1]`
+
+        To specify a range between lower and upper bound use:
+        1. `gt` - greater then - an exclusive lower bound
+        2. `ge` - greater or equal - an inclusive lower bound
+        3. `lt` - less then - an exclusive upper bound
+        4. `le` - less or equal - an inclusive upper bound
+        Example: `CasRange(ge=1, lt=3) # [1,3)`
+
+        If only one lower or upper bound is specified, the other bound will be assumed `unbounded`.
+        Example: `CasRange(ge=1) # [1, +infinity)`
+        """
+        if gt is not None:
+            self.key_min = dict(kind="excluded", value=gt)
+            self.repr_min = f'gt="{gt}"'
+        if ge is not None:
+            self.key_min = dict(kind="included", value=ge)
+            self.repr_min = f'ge="{ge}"'
+
+        if lt is not None:
+            self.key_max = dict(kind="excluded", value=lt)
+            self.repr_max = f'lt="{lt}"'
+        if le is not None:
+            self.key_max = dict(kind="included", value=le)
+            self.repr_max = f'le="{le}"'
+        if eq is not None:
+            self.key_min = dict(kind="included", value=eq)
+            self.key_max = dict(kind="included", value=eq)
+            self.repr_min = f'ge="{eq}"'
+            self.repr_max = f'le="{eq}"'
+
+
 color = SimpleNamespace(
     **{
         f"{prefix}{color}": f"\033[{ansi_color_code}{ansi_effect_code}m{{0}}\033[0m".format
@@ -465,7 +523,7 @@ class Instance:
         tuple: Any,  # TODO tuple, not any
         index: int | None = None,
         term: int | None = None,
-        range: Any | None = None,  # TODO better types for bounds
+        range: CasRange | None = None,  # TODO better types for bounds
     ) -> int:
         """
         Performs a clusterwide compare and swap operation.
@@ -482,7 +540,7 @@ class Instance:
 
         ASSUMPTIONS
         It is assumed that this operation is called on leader.
-        Failing to do so will result in error.
+        Failing to do so will result in an error.
         """
         if index is None:
             index = self.raft_index()
@@ -490,20 +548,18 @@ class Instance:
         elif term is None:
             term = self.raft_term_by_index(index)
 
+        predicate_range = None
         if range is not None:
-            key_min, key_max = range
-            key_min["value"] = msgpack.packb([key_min["value"]])
-            key_max["value"] = msgpack.packb([key_max["value"]])
-            range = dict(
+            predicate_range = dict(
                 space=space,
-                key_min=key_min,
-                key_max=key_max,
+                key_min=range.key_min_packed,
+                key_max=range.key_max_packed,
             )
 
         predicate = dict(
             index=index,
             term=term,
-            ranges=[range] if range is not None else [],
+            ranges=[predicate_range] if predicate_range is not None else [],
         )
 
         if dml_kind in ["insert", "replace"]:
@@ -873,7 +929,7 @@ class Cluster:
         tuple: Any,  # TODO tuple, not any
         index: int | None = None,
         term: int | None = None,
-        range: Any | None = None,  # TODO better types
+        range: CasRange | None = None,  # TODO better types
         # If specified send CaS through this instance
         instance: Instance | None = None,
     ) -> int:
@@ -900,21 +956,20 @@ class Cluster:
         elif term is None:
             term = instance.raft_term_by_index(index)
 
+        predicate_range = None
         if range is not None:
-            key_min, key_max = range
-            range = dict(
+            predicate_range = dict(
                 space=space,
-                index=instance.eval("return box.space[...].index[0].name", space),
-                key_min=key_min,
-                key_max=key_max,
+                key_min=range.key_min,
+                key_max=range.key_max,
             )
 
         predicate = dict(
             index=index,
             term=term,
-            ranges=[range] if range is not None else [],
+            ranges=[predicate_range] if predicate_range is not None else [],
         )
-        if dml_kind in ["insert", "replace"]:
+        if dml_kind in ["insert", "replace", "delete"]:
             dml = dict(
                 space=space,
                 kind=dml_kind,
diff --git a/test/int/test_cas.py b/test/int/test_cas.py
index 3fa674406a15444ba3e4c5fcf3c52d533acfca8f..31d3a321a9e5dea5b8c4ed2ab9da6eb1ce65db5a 100644
--- a/test/int/test_cas.py
+++ b/test/int/test_cas.py
@@ -1,5 +1,5 @@
 import pytest
-from conftest import Instance, TarantoolError
+from conftest import Instance, TarantoolError, CasRange
 
 _3_SEC = 3
 
@@ -88,10 +88,7 @@ def test_cas_errors(instance: Instance):
                 "insert",
                 space,
                 [0],
-                range=(
-                    dict(kind="included", value=0),
-                    dict(kind="included", value=0),
-                ),
+                range=CasRange(eq=0),
             )
         assert e5.value.args == (
             "ER_PROC_C",
@@ -127,10 +124,7 @@ def test_cas_predicate(instance: Instance):
             "_pico_property",
             ["fruit", "orange"],
             index=read_index,
-            range=(
-                dict(kind="included", value="fruit"),
-                dict(kind="included", value="fruit"),
-            ),
+            range=CasRange(eq="fruit"),
         )
     assert e5.value.args == (
         "ER_PROC_C",
@@ -145,10 +139,7 @@ def test_cas_predicate(instance: Instance):
         "_pico_property",
         ["flower", "tulip"],
         index=read_index,
-        range=(
-            dict(kind="included", value="flower"),
-            dict(kind="included", value="flower"),
-        ),
+        range=CasRange(eq="flower"),
     )
     assert ret == read_index + 2
     instance.call(".proc_sync_raft", ret, (_3_SEC, 0))