diff --git a/meta/lib/oeqa/core/case.py b/meta/lib/oeqa/core/case.py
index e71cab5028c..86944cddde0 100644
--- a/meta/lib/oeqa/core/case.py
+++ b/meta/lib/oeqa/core/case.py
@@ -32,33 +32,18 @@ class OETestCase(unittest.TestCase):
     # OEQAMissingVariable exception is raised
     td_vars = None
 
-    @classmethod
-    def _oeSetUpClass(clss):
-        _validate_td_vars(clss.td, clss.td_vars, "class")
-        if hasattr(clss, 'setUpHooker') and callable(getattr(clss, 'setUpHooker')):
-            clss.setUpHooker()
-        clss.setUpClassMethod()
-
-    @classmethod
-    def _oeTearDownClass(clss):
-        clss.tearDownClassMethod()
-
-    def _oeSetUp(self):
-        # unittest doesn't call tearDown() if setUp() fails so the decorators
-        # need tearing down here in that case too
-        try:
-            for d in self.decorators:
-                d.setUpDecorator()
-            self.setUpMethod()
-        except:
-            for d in self.decorators:
-                d.tearDownDecorator()
-            raise
-
-    def _oeTearDown(self):
+    # Decorators bound to this test case by OETestLoader
+    decorators = ()
+
+    def _callSetUp(self):
+        # unittest.TestCase.run() calls this to run setUp(). Check the test
+        # data and set up the decorators first. Decorators are torn down as
+        # cleanups, which run after tearDown() and also if setUp() fails.
+        _validate_td_vars(self.td, self.td_vars, "class")
         for d in self.decorators:
-            d.tearDownDecorator()
-        self.tearDownMethod()
+            d.setUpDecorator()
+            self.addCleanup(d.tearDownDecorator)
+        super()._callSetUp()
 
     def assertFileExists(self, filename, msg=None):
         """
diff --git a/meta/lib/oeqa/core/context.py b/meta/lib/oeqa/core/context.py
index 3bd65ba35f6..601a8014d9b 100644
--- a/meta/lib/oeqa/core/context.py
+++ b/meta/lib/oeqa/core/context.py
@@ -47,24 +47,17 @@ class OETestContext:
         return modules
 
     def skipTests(self, skips):
-        if not skips:
-            return
-        def skipfuncgen(skipmsg):
-            def func():
-                raise unittest.SkipTest(skipmsg)
-            return func
-        class_ids = {}
+        # Use unittest's skip support so that skipped tests, and the class
+        # setup of skipped classes, don't run
         for test in self.suites:
-            if test.__class__ not in class_ids:
-                class_ids[test.__class__] = '.'.join(test.id().split('.')[:-1])
+            class_id = test.id().rsplit('.', 1)[0]
             for skip in skips:
-                if (test.id()+'.').startswith(skip+'.'):
-                    setattr(test, 'setUp', skipfuncgen('Skip by the command line argument "%s"' % skip))
-        for tclass in class_ids:
-            cid = class_ids[tclass]
-            for skip in skips:
-                if (cid + '.').startswith(skip + '.'):
-                    setattr(tclass, 'setUpHooker', skipfuncgen('Skip by the command line argument "%s"' % skip))
+                msg = 'Skip by the command line argument "%s"' % skip
+                if (class_id + '.').startswith(skip + '.'):
+                    unittest.skip(msg)(test.__class__)
+                elif (test.id() + '.').startswith(skip + '.'):
+                    method = getattr(test, test._testMethodName)
+                    setattr(test, test._testMethodName, unittest.skip(msg)(method))
 
     def loadTests(self, module_paths, modules=[], tests=[],
             modules_manifest="", modules_required=[], **kwargs):
diff --git a/meta/lib/oeqa/core/loader.py b/meta/lib/oeqa/core/loader.py
index 94ade54506d..d4f330dafc3 100644
--- a/meta/lib/oeqa/core/loader.py
+++ b/meta/lib/oeqa/core/loader.py
@@ -171,37 +171,9 @@ class OETestLoader(unittest.TestLoader):
         return False
 
     def _getTestCase(self, testCaseClass, tcName):
-        if not hasattr(testCaseClass, '__oeqa_loader') and \
-                issubclass(testCaseClass, OETestCase):
-            # In order to support data_vars validation
-            # monkey patch the default setUp/tearDown{Class} to use
-            # the ones provided by OETestCase
-            setattr(testCaseClass, 'setUpClassMethod',
-                    getattr(testCaseClass, 'setUpClass'))
-            setattr(testCaseClass, 'tearDownClassMethod',
-                    getattr(testCaseClass, 'tearDownClass'))
-            setattr(testCaseClass, 'setUpClass',
-                    testCaseClass._oeSetUpClass)
-            setattr(testCaseClass, 'tearDownClass',
-                    testCaseClass._oeTearDownClass)
-
-            # In order to support decorators initialization
-            # monkey patch the default setUp/tearDown to use
-            # a setUpDecorators/tearDownDecorators that methods
-            # will call setUp/tearDown original methods.
-            setattr(testCaseClass, 'setUpMethod',
-                    getattr(testCaseClass, 'setUp')) 
-            setattr(testCaseClass, 'tearDownMethod',
-                    getattr(testCaseClass, 'tearDown'))
-            setattr(testCaseClass, 'setUp', testCaseClass._oeSetUp)
-            setattr(testCaseClass, 'tearDown', testCaseClass._oeTearDown)
-
-            setattr(testCaseClass, '__oeqa_loader', True)
-
         case = testCaseClass(tcName)
         if isinstance(case, OETestCase):
-            setattr(case, 'decorators', [])
-
+            case.decorators = []
         return case
 
     def loadTestsFromTestCase(self, testCaseClass):
