diff --git a/kgb/calls.py b/kgb/calls.py
new file mode 100644
index 0000000000000000000000000000000000000000..77111f43f0829d696bd0c66e7999af9890c67e7f
--- /dev/null
+++ b/kgb/calls.py
@@ -0,0 +1,130 @@
+"""Call tracking and checks for spiess."""
+
+from __future__ import unicode_literals
+
+from kgb.pycompat import iteritems, text_type
+from kgb.signature import FunctionSig
+
+
+class SpyCall(object):
+    """Records arguments made to a spied function call.
+
+    SpyCalls are created and stored by a FunctionSpy every time it is
+    called. They're accessible through the FunctionSpy's ``calls`` attribute.
+    """
+
+    def __init__(self, spy, args, kwargs):
+        """Initialize the call.
+
+        Args:
+            spy (kgb.spies.FunctionSpy):
+                The function spy that the call was made on.
+
+            args (tuple):
+                A tuple of positional arguments from the spy. These correspond
+                to positional arguments in the function's signature.
+
+            kwargs (dict):
+                A dictionary of keyword arguments from the spy. These
+                correspond to keyword arguments in the function's signature.
+        """
+        self.spy = spy
+        self.args = args
+        self.kwargs = kwargs
+        self.return_value = None
+        self.exception = None
+
+    def called_with(self, *args, **kwargs):
+        """Return whether this call was made with the given arguments.
+
+        Not every argument and keyword argument made in the call must be
+        provided to this method. These can be a subset of the positional and
+        keyword arguments in the call, but cannot contain any arguments not
+        made in the call.
+
+        Args:
+            *args (tuple):
+                The positional arguments made in the call, or a subset of
+                those arguments (starting with the first argument).
+
+            **kwargs (dict):
+                The keyword arguments made in the call, or a subset of those
+                arguments.
+
+        Returns:
+            bool:
+            ``True`` if the call's arguments match the provided arguments.
+            ``False`` if they do not.
+        """
+        if len(args) > len(self.args):
+            return False
+
+        if self.args[:len(args)] != args:
+            return False
+
+        pos_args = self.spy._sig.arg_names
+
+        if self.spy.func_type in (FunctionSig.TYPE_BOUND_METHOD,
+                                  FunctionSig.TYPE_UNBOUND_METHOD):
+            pos_args = pos_args[1:]
+
+        all_args = dict(zip(pos_args, self.args))
+        all_args.update(self.kwargs)
+
+        for key, value in iteritems(kwargs):
+            if key not in all_args or all_args[key] != value:
+                return False
+
+        return True
+
+    def returned(self, value):
+        """Return whether this call returned the given value.
+
+        Args:
+            value (object):
+                The expected returned value from the call.
+
+        Returns:
+            bool:
+            ``True`` if this call returned the given value. ``False`` if it
+            did not.
+        """
+        return self.return_value == value
+
+    def raised(self, exception_cls):
+        """Return whether this call raised this exception.
+
+        Args:
+            exception_cls (type):
+                The expected type of exception raised by the call.
+
+        Returns:
+            bool:
+            ``True`` if this call raised the given exception type.
+            ``False`` if it did not.
+        """
+        return ((self.exception is None and exception_cls is None) or
+                type(self.exception) is exception_cls)
+
+    def raised_with_message(self, exception_cls, message):
+        """Return whether this call raised this exception and message.
+
+        Args:
+            exception_cls (type):
+                The expected type of exception raised by the call.
+
+            message (unicode):
+                The expected message from the exception.
+
+        Returns:
+            bool:
+            ``True`` if this call raised the given exception type and message.
+            ``False`` if it did not.
+        """
+        return (self.exception is not None and
+                self.raised(exception_cls) and
+                text_type(self.exception) == message)
+
+    def __repr__(self):
+        return '<SpyCall(args=%r, kwargs=%r, returned=%r, raised=%r>' % (
+            self.args, self.kwargs, self.return_value, self.exception)
diff --git a/kgb/spies.py b/kgb/spies.py
index c66722ce5fc01b93a3ee6b4065fa815931808036..6a7d447b90279e41b3ba179966dde0bddef619d6 100644
--- a/kgb/spies.py
+++ b/kgb/spies.py
@@ -4,138 +4,15 @@ import copy
 import inspect
 import types
 
+from kgb.calls import SpyCall
 from kgb.errors import (ExistingSpyError,
                         IncompatibleFunctionError,
                         InternalKGBError)
-from kgb.pycompat import iteritems, iterkeys, pyver, text_type
+from kgb.pycompat import iterkeys, pyver
 from kgb.signature import FunctionSig, _UNSET_ARG
 from kgb.utils import is_attr_defined_on_ancestor
 
 
-class SpyCall(object):
-    """Records arguments made to a spied function call.
-
-    SpyCalls are created and stored by a FunctionSpy every time it is
-    called. They're accessible through the FunctionSpy's ``calls`` attribute.
-    """
-
-    def __init__(self, spy, args, kwargs):
-        """Initialize the call.
-
-        Args:
-            spy (FunctionSpy):
-                The function spy that the call was made on.
-
-            args (tuple):
-                A tuple of positional arguments from the spy. These correspond
-                to positional arguments in the function's signature.
-
-            kwargs (dict):
-                A dictionary of keyword arguments from the spy. These
-                correspond to keyword arguments in the function's signature.
-        """
-        self.spy = spy
-        self.args = args
-        self.kwargs = kwargs
-        self.return_value = None
-        self.exception = None
-
-    def called_with(self, *args, **kwargs):
-        """Return whether this call was made with the given arguments.
-
-        Not every argument and keyword argument made in the call must be
-        provided to this method. These can be a subset of the positional and
-        keyword arguments in the call, but cannot contain any arguments not
-        made in the call.
-
-        Args:
-            *args (tuple):
-                The positional arguments made in the call, or a subset of
-                those arguments (starting with the first argument).
-
-            **kwargs (dict):
-                The keyword arguments made in the call, or a subset of those
-                arguments.
-
-        Returns:
-            bool:
-            ``True`` if the call's arguments match the provided arguments.
-            ``False`` if they do not.
-        """
-        if len(args) > len(self.args):
-            return False
-
-        if self.args[:len(args)] != args:
-            return False
-
-        pos_args = self.spy._sig.arg_names
-
-        if self.spy.func_type in (FunctionSpy.TYPE_BOUND_METHOD,
-                                  FunctionSpy.TYPE_UNBOUND_METHOD):
-            pos_args = pos_args[1:]
-
-        all_args = dict(zip(pos_args, self.args))
-        all_args.update(self.kwargs)
-
-        for key, value in iteritems(kwargs):
-            if key not in all_args or all_args[key] != value:
-                return False
-
-        return True
-
-    def returned(self, value):
-        """Return whether this call returned the given value.
-
-        Args:
-            value (object):
-                The expected returned value from the call.
-
-        Returns:
-            bool:
-            ``True`` if this call returned the given value. ``False`` if it
-            did not.
-        """
-        return self.return_value == value
-
-    def raised(self, exception_cls):
-        """Return whether this call raised this exception.
-
-        Args:
-            exception_cls (type):
-                The expected type of exception raised by the call.
-
-        Returns:
-            bool:
-            ``True`` if this call raised the given exception type.
-            ``False`` if it did not.
-        """
-        return ((self.exception is None and exception_cls is None) or
-                type(self.exception) is exception_cls)
-
-    def raised_with_message(self, exception_cls, message):
-        """Return whether this call raised this exception and message.
-
-        Args:
-            exception_cls (type):
-                The expected type of exception raised by the call.
-
-            message (unicode):
-                The expected message from the exception.
-
-        Returns:
-            bool:
-            ``True`` if this call raised the given exception type and message.
-            ``False`` if it did not.
-        """
-        return (self.exception is not None and
-                self.raised(exception_cls) and
-                text_type(self.exception) == message)
-
-    def __repr__(self):
-        return '<SpyCall(args=%r, kwargs=%r, returned=%r, raised=%r>' % (
-            self.args, self.kwargs, self.return_value, self.exception)
-
-
 class FunctionSpy(object):
     """A spy infiltrating a function.
 
diff --git a/kgb/tests/test_function_spy.py b/kgb/tests/test_function_spy.py
index cc66a4870c2f73d5254d854fd91e0f6dab53ffcb..2ff7133435829d08ad4e76027089a16e75affd3c 100644
--- a/kgb/tests/test_function_spy.py
+++ b/kgb/tests/test_function_spy.py
@@ -6,8 +6,8 @@ import re
 import types
 
 from kgb.errors import ExistingSpyError, IncompatibleFunctionError
+from kgb.pycompat import text_type
 from kgb.signature import FunctionSig
-from kgb.spies import text_type
 from kgb.tests.base import MathClass, TestCase
 
 
diff --git a/kgb/tests/test_spy_call.py b/kgb/tests/test_spy_call.py
index 10df46fd30675b351998512c2fe375799be73192..0bf02a550a0ce9563006a8dc60f37895c9939d08 100644
--- a/kgb/tests/test_spy_call.py
+++ b/kgb/tests/test_spy_call.py
@@ -1,6 +1,6 @@
 from __future__ import unicode_literals
 
-from kgb.spies import text_type
+from kgb.pycompat import text_type
 from kgb.tests.base import MathClass, TestCase
 
 
