diff --git a/kgb/spies.py b/kgb/spies.py
index 6a2bc46ccf82b29e7527671e34706b25489285ad..b1ab5dddb0f32656dff6174b97a946ae70a0cf94 100644
--- a/kgb/spies.py
+++ b/kgb/spies.py
@@ -2,12 +2,16 @@ from __future__ import absolute_import, unicode_literals
 
 import copy
 import inspect
+import logging
 import sys
 import types
 
 from kgb.errors import ExistingSpyError, IncompatibleFunctionError
 
 
+logger = logging.getLogger('kgb')
+
+
 pyver = sys.version_info[:2]
 
 if pyver[0] == 2:
@@ -213,7 +217,8 @@ class FunctionSpy(object):
 
     _spy_map = {}
 
-    def __init__(self, agency, func, call_fake=None, call_original=True):
+    def __init__(self, agency, func, call_fake=None, call_original=True,
+                 owner=_UNSET_ARG):
         """Initialize the spy.
 
         This will begin spying on the provided function or method, injecting
@@ -266,14 +271,21 @@ class FunctionSpy(object):
 
         # Determine if this is a method, and if so, what type and what owns it.
         if pyver[0] == 2 and inspect.ismethod(func):
-            owner = getattr(func, METHOD_SELF_ATTR)
+            method_owner = getattr(func, METHOD_SELF_ATTR)
 
-            if owner is None:
+            if method_owner is None:
                 self.func_type = self.TYPE_UNBOUND_METHOD
                 self.owner = func.im_class
+
+                if owner is _UNSET_ARG:
+                    logger.warning('Unbound method owners can easily be '
+                                   'determined on Python 2.x, but not on '
+                                   '3.x. Please pass owner= to spy_on() '
+                                   'to set a specific owner for %r.',
+                                   func)
             else:
                 self.func_type = self.TYPE_BOUND_METHOD
-                self.owner = owner
+                self.owner = method_owner
         elif pyver[0] >= 3:
             # Python 3 does not officially have unbound methods. Methods on
             # instances are easily identified as types.MethodType, but
@@ -294,20 +306,51 @@ class FunctionSpy(object):
             if inspect.ismethod(func):
                 self.func_type = self.TYPE_BOUND_METHOD
                 self.owner = getattr(func, METHOD_SELF_ATTR)
-            elif ('.' in func.__qualname__ and
-                  '<locals>' not in func.__qualname__):
-                owner = inspect.getmodule(real_func)
-
-                for part in real_func.__qualname__.split('.')[:-1]:
-                    try:
-                        owner = getattr(owner, part)
-                    except AttributeError:
-                        owner = None
-                        break
-
-                if owner is not None:
-                    self.func_type = self.TYPE_UNBOUND_METHOD
+            elif '.' in func.__qualname__:
+                if owner is not _UNSET_ARG:
                     self.owner = owner
+                    self.func_type = self.TYPE_UNBOUND_METHOD
+                elif '<locals>' in func.__qualname__:
+                    # We can only assume this is a function. It might not be.
+                    self.func_type = self.TYPE_FUNCTION
+                else:
+                    method_owner = inspect.getmodule(real_func)
+
+                    for part in real_func.__qualname__.split('.')[:-1]:
+                        try:
+                            method_owner = getattr(method_owner, part)
+                        except AttributeError:
+                            method_owner = None
+                            break
+
+                    if method_owner is not None:
+                        self.func_type = self.TYPE_UNBOUND_METHOD
+                        self.owner = method_owner
+
+                    logger.warning('Determined the owner of %r to be %r, '
+                                   'but it may be wrong. Please pass '
+                                   'owner= to spy_on() to set a specific '
+                                   'owner.',
+                                   func, self.owner)
+
+        # If the caller passed an explicit owner, check to see if it's at all
+        # valid. Note that it may have been handled above (for unbound
+        # methods).
+        if owner is not _UNSET_ARG and owner is not self.owner:
+            if self.func_type == self.TYPE_FUNCTION:
+                raise ValueError(
+                    'This function has no owner, but an owner was passed '
+                    'to spy_on().')
+            else:
+                if not hasattr(owner, self.func_name):
+                    raise ValueError('The owner passed does not contain the '
+                                     'spied method.')
+                elif (self.func_type == self.TYPE_BOUND_METHOD or
+                      (pyver[0] == 2 and
+                       self.func_type == self.TYPE_UNBOUND_METHOD)):
+                    raise ValueError(
+                        'The owner passed does not match the actual owner of '
+                        'the bound method.')
 
         if (self.owner is not None and
             (not inspect.isclass(self.owner) or
diff --git a/kgb/tests/test_function_spy.py b/kgb/tests/test_function_spy.py
index 4e07613869dbe414a014670bb59438408b0108bc..308106fd2806639fc175651f8e34a940bb3caaf7 100644
--- a/kgb/tests/test_function_spy.py
+++ b/kgb/tests/test_function_spy.py
@@ -196,6 +196,15 @@ class FunctionSpyTests(TestCase):
         self.assertEqual(spy.func_type, spy.TYPE_BOUND_METHOD)
         self.assertIsInstance(MathClass.class_do_math, types.MethodType)
 
+    def test_construction_with_function_and_owner(self):
+        """Testing FunctionSpy constructions with function and owner passed"""
+        with self.assertRaises(ValueError) as cm:
+            self.agency.spy_on(do_math, owner=AdderObject)
+
+        self.assertEqual(text_type(cm.exception),
+                         'This function has no owner, but an owner was '
+                         'passed to spy_on().')
+
     def test_construction_with_classmethod_on_parent(self):
         """Testing FunctionSpy construction with classmethod from parent of
         class
@@ -328,6 +337,43 @@ class FunctionSpyTests(TestCase):
         obj2 = MyObject()
         self.assertFalse(hasattr(obj2.foo, 'spy'))
 
+    def test_construction_with_bound_method_and_bad_owner(self):
+        """Testing FunctionSpy constructions with a bound method and an
+        explicit owner not matching the class
+        """
+        class MyObject(object):
+            def foo(self):
+                pass
+
+        class BadObject(object):
+            def foo(self):
+                pass
+
+        obj = MyObject()
+
+        with self.assertRaises(ValueError) as cm:
+            self.agency.spy_on(obj.foo, owner=BadObject)
+
+        self.assertEqual(text_type(cm.exception),
+                         'The owner passed does not match the actual owner '
+                         'of the bound method.')
+
+    def test_construction_with_owner_without_method(self):
+        """Testing FunctionSpy constructions with an owner passed that does
+        not provide the spied method
+        """
+        class MyObject(object):
+            def foo(self):
+                pass
+
+        obj = MyObject()
+
+        with self.assertRaises(ValueError) as cm:
+            self.agency.spy_on(obj.foo, owner=AdderObject)
+
+        self.assertEqual(text_type(cm.exception),
+                         'The owner passed does not contain the spied method.')
+
     def test_construction_with_non_function(self):
         """Testing FunctionSpy constructions with non-function"""
         with self.assertRaises(ValueError) as cm:
