def make_error_extraction_tests(get_messages):
    class ErrorFieldExtraction(TestCase):
        """
        Tests for extracting fields from exceptions in failed actions.
        """
        def test_matching_class(self):
            """
            If an exception fails an action and the exact type has registered
            extractor, extract errors using it.
            """
            class MyException(Exception):
                pass
            register_exception_extractor(MyException,
                                         lambda e: {"key": e.args[0]})
            exception = MyException("a value")
            [message] = get_messages(exception)
            assertContainsFields(self, message, {"key": "a value"})

        def test_subclass_falls_back_to_parent(self):
            """
            If an exception fails an action and the exact type has not been
            registered but the error is a subclass of a registered class,
            extract errors using it.
            """
            class MyException(Exception):
                pass

            class SubException(MyException):
                pass

            register_exception_extractor(MyException,
                                         lambda e: {"key": e.args[0]})
            [message] = get_messages(SubException("the value"))
            assertContainsFields(self, message, {"key": "the value"})

        def test_subclass_matches_first(self):
            """
            If both a superclass and base class have registered extractors, the
            more specific one is used.
            """
            class MyException(Exception):
                pass

            class SubException(MyException):
                pass

            class SubSubException(SubException):
                pass

            register_exception_extractor(MyException,
                                         lambda e: {"parent": e.args[0]})
            register_exception_extractor(SubException,
                                         lambda e: {"child": e.args[0]})
            [message] = get_messages(SubSubException("the value"))
            assertContainsFields(self, message, {"child": "the value"})

        def test_error_in_extracter(self):
            """
            If an error occurs in extraction, log the message as usual just
            without the extra fields, and an additional traceback.
            """
            class MyException(Exception):
                pass

            def extract(e):
                return e.nosuchattribute
            register_exception_extractor(MyException, extract)

            messages = get_failed_action_messages(MyException())
            assertContainsFields(self, messages[1],
                                 {"action_type": "sys:me",
                                  "action_status": "failed"})
            assertContainsFields(self, messages[0],
                                 {"message_type": "eliot:traceback"})
            self.assertIn("nosuchattribute", str(messages[0]["reason"]))

        def test_environmenterror(self):
            """
            ``EnvironmentError`` has a registered extractor that extracts the
            errno.
            """
            [message] = get_messages(EnvironmentError(12, "oh noes"))
            assertContainsFields(self, message, {"errno": 12})

    return ErrorFieldExtraction
Create a test case class for testing extraction of fields from exceptions.
dataset/ETHPy150Open ClusterHQ/eliot/eliot/tests/test_action.py/make_error_extraction_tests