Change test case filter to use callable() instead of inspect.ismethod() (#648)

diff --git a/mobly/base_test.py b/mobly/base_test.py
index 348a606..2d386b1 100644
--- a/mobly/base_test.py
+++ b/mobly/base_test.py
@@ -737,7 +737,7 @@
             A list of strings, each is a test method name.
         """
         test_names = []
-        for name, _ in inspect.getmembers(self, inspect.ismethod):
+        for name, _ in inspect.getmembers(self, callable):
             if name.startswith('test_'):
                 test_names.append(name)
         return test_names + list(self._generated_test_table.keys())
diff --git a/tests/mobly/base_test_test.py b/tests/mobly/base_test_test.py
index 891f4fb..03c929c 100755
--- a/tests/mobly/base_test_test.py
+++ b/tests/mobly/base_test_test.py
@@ -13,6 +13,7 @@
 # limitations under the License.
 
 import copy
+import functools
 import io
 import os
 import mock
@@ -203,10 +204,43 @@
                 never_call()
 
         bt_cls = MockBaseTest(self.mock_test_cls_configs)
-        bt_cls.run(test_names=["test_something"])
+        bt_cls.run()
         actual_record = bt_cls.results.passed[0]
         self.assertEqual(actual_record.test_name, "test_something")
 
+    def test_default_execution_skip_noncallable_tests(self):
+        mock_decorated = mock.MagicMock()
+        mock_undecorated = mock.MagicMock()
+
+        class TestDecorator(object):
+            def __init__(self, func):
+                self.func = func
+
+            def __call__(self, *args, **kwargs):
+                return self.func(*args, **kwargs)
+
+            def __get__(self, instance, owner):
+                return functools.partial(self.__call__, instance)
+
+        class MockBaseTest(base_test.BaseTestClass):
+            def __init__(self, controllers):
+                super(MockBaseTest, self).__init__(controllers)
+                self.test_noncallable = None
+
+            @TestDecorator
+            def test_decorated(self):
+                mock_decorated('test_decorated')
+
+            def test_undecorated(self):
+                mock_undecorated('test_undecorated')
+
+        bt_cls = MockBaseTest(self.mock_test_cls_configs)
+        bt_cls.run()
+        self.assertNotIn('test_noncallable',
+                         [test.test_name for test in bt_cls.results.executed])
+        mock_decorated.assert_called_once_with('test_decorated')
+        mock_undecorated.assert_called_once_with('test_undecorated')
+
     def test_missing_requested_test_func(self):
         class MockBaseTest(base_test.BaseTestClass):
             pass