Repository: nose-devs/nose2

Issue:
Failed to run a specific test with mock.patch decorator using nose2
This is my test file `test_mock.py` that minimally reproduces the failure:

```
import unittest
from unittest.mock import patch

class TestMock(unittest.TestCase):

    @patch("urllib3.PoolManager")
    def test_foo(self, mock_urllib3_poolmanager):
        pass
```

When I use nose2 to run all tests in this file. Everything works.

```
bash-4.2# nose2 test_mock
.
----------------------------------------------------------------------
Ran 1 test in 0.102s

OK
```

But when I use nose2 to select a specific test to run. It throws an error.

```
bash-4.2# nose2 test_mock.TestMock.test_foo
E
======================================================================
ERROR: test_mock.transplant_class.<locals>.C (test_foo)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/var/lang/lib/python3.7/unittest/mock.py", line 1256, in patched
    return func(*args, **keywargs)
TypeError: test_foo() missing 1 required positional argument: 'mock_urllib3_poolmanager'

----------------------------------------------------------------------
Ran 1 test in 0.087s

FAILED (errors=1)
```

Any insight is greatly appreciated. Thanks!

Discussion:

Patch:
diff --git a/nose2/plugins/loader/functions.py b/nose2/plugins/loader/functions.py
index d7b6563..5bd7212 100644
--- a/nose2/plugins/loader/functions.py
+++ b/nose2/plugins/loader/functions.py
@@ -87,6 +87,7 @@ class Functions(Plugin):
 
         parent, obj, name, index = result
         if (isinstance(obj, types.FunctionType) and not
+            isinstance(parent, type) and not
             util.isgenerator(obj) and not
             hasattr(obj, 'paramList') and
             util.num_expected_args(obj) == 0):


Test patch:
diff --git a/nose2/tests/unit/test_functions_loader.py b/nose2/tests/unit/test_functions_loader.py
index cf1d6fd..e6fd25d 100644
--- a/nose2/tests/unit/test_functions_loader.py
+++ b/nose2/tests/unit/test_functions_loader.py
@@ -1,4 +1,11 @@
 import unittest
+
+try:
+    from unittest import mock
+except ImportError:
+    # Python versions older than 3.3 don't have mock by default
+    import mock
+
 from nose2 import events, loader, session
 from nose2.plugins.loader import functions
 from nose2.tests._common import TestCase
@@ -47,3 +54,37 @@ class TestFunctionLoader(TestCase):
         event = events.LoadFromModuleEvent(self.loader, m)
         self.session.hooks.loadTestsFromModule(event)
         self.assertEqual(len(event.extraTests), 0)
+
+    def test_can_load_test_functions_from_name(self):
+        event = events.LoadFromNameEvent(self.loader, __name__+'.func', None)
+        suite = self.session.hooks.loadTestsFromName(event)
+        self.assertNotEqual(suite, None)
+
+    def test_ignores_test_methods_from_name(self):
+        # Should ignore test methods even when specified directly
+        event = events.LoadFromNameEvent(self.loader, __name__+'.Case.test_method', None)
+        suite = self.session.hooks.loadTestsFromName(event)
+        self.assertEqual(suite, None)
+
+    def test_ignores_decorated_test_methods_from_name(self):
+        # Should ignore test methods even when they are of FunctionType
+        event = events.LoadFromNameEvent(self.loader, __name__+'.Case.test_patched', None)
+        suite = self.session.hooks.loadTestsFromName(event)
+        self.assertEqual(suite, None)
+
+
+def func():
+    pass
+
+def dummy():
+    pass
+
+class Case(unittest.TestCase):
+    __test__ = False # do not run this
+
+    def test_method(self):
+        pass
+
+    @mock.patch(__name__+'.dummy')
+    def test_patched(self, mock):
+        pass