コード例 #1
0
def hydrated_client():
    """Create a Falcon API with an endpoint for testing Marshmallow"""
    data_store = DataStore()

    class PhilosopherResource:

        schema = Philosopher()

        def on_get(self, req, resp, phil_id):
            """Get a philosopher"""
            req.context["result"] = data_store.get(phil_id)

    class PhilosopherCollection:

        schema = Philosopher()

        def on_post(self, req, resp):
            req.context["result"] = data_store.insert(req.context["json"])

    app = API(middleware=[m.Marshmallow()])

    app.add_route("/philosophers", PhilosopherCollection())
    app.add_route("/philosophers/{phil_id}", PhilosopherResource())

    yield testing.TestClient(app)

    data_store.clear()
コード例 #2
0
def hydrated_client_multiple_middleware():
    """A Falcon API with an endpoint for testing Marshmallow, with all
    included middlewares registered."""
    data_store = DataStore()

    class PhilosopherResource:

        schema = Philosopher()

        def on_get(self, req, resp, phil_id):
            """Get a philosopher"""
            req.context['result'] = data_store.get(phil_id)

    class PhilosopherCollection:

        schema = Philosopher()

        def on_post(self, req, resp):
            req.context['result'] = data_store.insert(req.context['json'])

    app = API(middleware=[
        m.Marshmallow(),
        m.JSONEnforcer(),
        m.EmptyRequestDropper()])

    app.add_route('/philosophers', PhilosopherCollection())
    app.add_route('/philosophers/{phil_id}', PhilosopherResource())

    yield testing.TestClient(app)

    data_store.clear()
コード例 #3
0
def hydrated_client_multiple_middleware():
    """Create a server for testing, with all included middlewares"""

    data_store = DataStore()

    class PhilosopherResource:

        schema = Philosopher()

        def on_get(self, req, resp, phil_id):
            """Get a philosopher"""
            req.context["result"] = data_store.get(phil_id)

    class PhilosopherCollection:

        schema = Philosopher()

        def on_post(self, req, resp):
            req.context["result"] = data_store.insert(req.context["json"])

    app = API(middleware=[
        m.Marshmallow(),
        m.JSONEnforcer(),
        m.EmptyRequestDropper()
    ])

    app.add_route("/philosophers", PhilosopherCollection())
    app.add_route("/philosophers/{phil_id}", PhilosopherResource())

    yield testing.TestClient(app)

    data_store.clear()
コード例 #4
0
    def test_process_resource(self, stream, schema, schema_err, bad_sch,
                              bad_uni, force_json, json_err, exp_ret):
        # type: (str, bool, bool, bool, bool, bool, bool, dict) -> None
        """Test processing a resource

        :param stream: the return of req.stream.read()
        :param schema: whether a schema should be returned (TestSchema)
        :param schema_err: whether a schema error is expected
        :param bad_sch: pass an uninstantiated or non-schema object
        :param bad_uni: whether bad unicode is expected
        :param force_json: whether to try json if no schema is found
        :param json_err: whether a JSON error is expected
        :param exp_ret: expected return if no errors are raised
        """
        mw = mid.Marshmallow()

        mw._force_json = force_json
        if schema:
            if bad_sch:
                mw._get_schema = lambda *x, **y: self.FooSchema
            else:
                mw._get_schema = lambda *x, **y: self.FooSchema()
        else:
            mw._get_schema = lambda *x, **y: None

        req = mock.Mock(method='GET')
        if not bad_uni:
            req.stream.read.return_value = stream.encode()
        else:
            req.stream.read.return_value = stream.encode() + b'\xe7'
        req.context = {}

        if schema_err:
            with pytest.raises(errors.HTTPUnprocessableEntity):
                # noinspection PyTypeChecker
                mw.process_resource(req, 'foo', 'foo', 'foo')
            return
        if bad_uni:
            with pytest.raises(errors.HTTPBadRequest):
                # noinspection PyTypeChecker
                mw.process_resource(req, 'foo', 'foo', 'foo')
            return
        if bad_sch:
            with pytest.raises(TypeError):
                # noinspection PyTypeChecker
                mw.process_resource(req, 'foo', 'foo', 'foo')
            return
        if json_err:
            with pytest.raises(errors.HTTPBadRequest):
                # noinspection PyTypeChecker
                mw.process_resource(req, 'foo', 'foo', 'foo')
            return

        # noinspection PyTypeChecker
        mw.process_resource(req, 'foo', 'foo', 'foo')
        if schema or force_json:
            assert req.context[mw._req_key] == exp_ret
        else:
            assert mw._req_key not in req.context
コード例 #5
0
    def test_process_response(self, res, schema, sch_err, bad_sch, force_json,
                              json_err, exp_ret):
        """Test process_response

        :param res: the value to put in the result key on req.context
        :param schema: whether a schema should be available
        :param sch_err: whether an error is expected dumping the data
        :param bad_sch: pass an uninstantiated or non-schema object
        :param force_json: whether force_json is true
        :param json_err: whether an error is expected dumping the data
        :param exp_ret: expected return if no errors are raised
        """
        mw = mid.Marshmallow()

        mw._force_json = force_json
        if schema:
            if bad_sch:
                mw._get_schema = lambda *x, **y: self.FooSchema
            else:
                mw._get_schema = lambda *x, **y: self.FooSchema()
        else:
            mw._get_schema = lambda *x, **y: None

        req = mock.Mock(method='GET')
        if res is None:
            req.context = {}
        else:
            req.context = {mw._resp_key: res}

        resp = mock.Mock()

        if bad_sch:
            with pytest.raises(TypeError):
                # noinspection PyTypeChecker
                mw.process_response(req, resp, 'foo', 'foo')
            return
        if sch_err:
            with pytest.raises(errors.HTTPInternalServerError):
                # noinspection PyTypeChecker
                mw.process_response(req, resp, 'foo', 'foo')
            return
        if json_err:
            with pytest.raises(errors.HTTPInternalServerError):
                # noinspection PyTypeChecker
                mw.process_response(req, resp, 'foo', 'foo')
            return

        # noinspection PyTypeChecker
        mw.process_response(req, resp, 'foo', 'foo')
        if res is None or (not schema and not force_json):
            # "body" has not been written, and is thus a mock object still
            assert isinstance(resp.body, mock.Mock)
        else:
            assert resp.body == exp_ret
コード例 #6
0
    def test_process_resource(self, stream, schema, schema_err, bad_sch,
                              force_json, json_err, exp_ret):
        # type: (str, bool, bool, bool, bool, bool, dict) -> None
        """Test processing a resource

        :param stream: the return of req.bounded_stream.read()
        :param schema: whether a schema should be returned (TestSchema)
        :param schema_err: whether a schema error is expected
        :param bad_sch: pass an uninstantiated or non-schema object
        :param force_json: whether to try json if no schema is found
        :param json_err: whether a JSON error is expected
        :param exp_ret: expected return if no errors are raised
        """
        mw = mid.Marshmallow()

        mw._force_json = force_json
        if schema:
            if bad_sch:
                setattr(mw, "_get_schema", lambda *_, **__: self.FooSchema)
            else:
                setattr(mw, "_get_schema", lambda *_, **__: self.FooSchema())
        else:
            setattr(mw, "_get_schema", lambda *_, **__: None)

        req = mock.Mock(method="GET")
        req.bounded_stream.read.return_value = stream
        req.context = {}

        if schema_err:
            with pytest.raises(errors.HTTPUnprocessableEntity):
                mw.process_resource(req, "foo", "foo", "foo")  # type: ignore
            return
        if bad_sch:
            with pytest.raises(TypeError):
                mw.process_resource(req, "foo", "foo", "foo")  # type: ignore
            return
        if json_err:
            with pytest.raises(errors.HTTPBadRequest):
                mw.process_resource(req, "foo", "foo", "foo")  # type: ignore
            return

        mw.process_resource(req, "foo", "foo", "foo")  # type: ignore
        if schema or force_json:
            assert req.context[mw._req_key] == exp_ret
        else:
            assert mw._req_key not in req.context
コード例 #7
0
    def test_get_schema(self, method, attrs, exp_value):
        # type: (str, tuple, str) -> None
        """Test getting a general or specific schema"""
        class TestResource:
            """Quick test object"""
            def __init__(self):
                for attr_name, value in attrs:
                    setattr(self, attr_name, value)

        tr = TestResource()

        val = mid.Marshmallow()._get_schema(tr, method, "response")

        if exp_value is None:
            assert val is None
        else:
            assert val == exp_value
コード例 #8
0
 def test_instantiation(self):
     """Test instantiating the class"""
     mid.Marshmallow()
コード例 #9
0
class TestMarshmallow:
    """Test Marshmallow middleware"""

    mw = mid.Marshmallow()

    class FooSchema(Schema):
        """Convert foo to bar for testing purposes"""
        bar = fields.String(load_from='foo', dump_to='foo')
        int = fields.Integer()

    def test_instantiation(self):
        """Test instantiating the class"""
        mid.Marshmallow()

    @pytest.mark.parametrize('method, attr_name, has_sch', [
        ('GET', 'get_schema', True),
        ('get', 'get_schema', True),
        ('get', 'schema', False),
        ('get', 'put_schema', False),
        ('POST', 'post_schema', True),
        ('post', 'post_schema', True),
        ('POST', 'schema', False),
        ('POST', 'get_schema', False),
        ('PATCH', 'patch_schema', True),
        ('patch', 'patch_schema', True),
        ('PUT', 'put_schema', True),
        ('put', 'put_schema', True),
        ('DELETE', 'delete_schema', True),
        ('delete', 'delete_schema', True),
    ])
    def test_get_method_schema(self, method, attr_name, has_sch):
        # type: (str, str, bool) -> None
        """Test getting a method-specific schema from a resource"""

        class TestResource:
            """Quick test object"""
            def __init__(self):
                setattr(self, attr_name, 'foo')

        tr = TestResource()

        sch = mid.Marshmallow._get_method_schema(tr, method)

        if has_sch:
            assert sch == 'foo'

        else:
            assert sch is None

    @pytest.mark.parametrize('method, attrs, exp_value', [
        ('GET', (('get_schema', 'foo'), ('schema', 'bar')), 'foo'),
        (
            'GET',
            (('get_schema', 'foo'), ('schema', 'bar'), ('post_schema', 'baz')),
            'foo'
        ),
        ('GET', (('post_schema', 'foo'), ('schema', 'bar')), 'bar'),
        ('GET', (('schema', 'bar'), ), 'bar'),
        ('GET', (), None),
    ])
    def test_get_schema(self, method, attrs, exp_value):
        # type: (str, tuple, str) -> None
        """Test getting a general or method-specific schema"""

        class TestResource:
            """Quick test object"""
            def __init__(self):
                for attr_name, value in attrs:
                    setattr(self, attr_name, value)

        tr = TestResource()

        val = mid.Marshmallow()._get_schema(tr, method)

        if exp_value is None:
            assert val is None
        else:
            assert val == exp_value

    @pytest.mark.parametrize(
        'stream, schema, schema_err, bad_sch, bad_uni, force_json, json_err, '
        'exp_ret', [
            (  # Good schema
                '{"foo": "test"}',
                True,
                False,
                False,
                False,
                False,
                False,
                {'bar': 'test'}
            ),
            (  # Schema errors on load
                '{"foo": "test", "int": "test"}',
                True,
                True,
                False,
                False,
                False,
                False,
                {'bar': 'test'}
            ),
            (  # Good schema, bad unicode in body
                '{"foo": "test"}',
                True,
                False,
                False,
                True,
                False,
                False,
                {'bar': 'test'}
            ),
            (  # Bad schema
                '{"foo": "test"}',
                True,
                False,
                True,
                False,
                False,
                False,
                {'bar': 'test'}
            ),
            (  # No schema, no force json (no change to req.context)
                '{"foo": "test"}',
                False,
                False,
                False,
                False,
                False,
                False,
                {'bar': 'test'}
            ),
            (  # No schema, force json
                '{"foo": "test"}',
                False,
                False,
                False,
                False,
                True,
                False,
                {'foo': 'test'}
            ),
            (  # No schema, force json, bad json
                '{"foo": }',
                False,
                False,
                False,
                False,
                True,
                True,
                {'foo': 'test'}
            ),
            (  # No schema, force json, good json, bad unicode
                '{"foo": "test"}',
                False,
                False,
                False,
                True,
                True,
                False,
                {'foo': 'test'}
            ),
        ]
    )
    def test_process_resource(self, stream, schema, schema_err, bad_sch,
                              bad_uni, force_json, json_err, exp_ret):
        # type: (str, bool, bool, bool, bool, bool, bool, dict) -> None
        """Test processing a resource

        :param stream: the return of req.stream.read()
        :param schema: whether a schema should be returned (TestSchema)
        :param schema_err: whether a schema error is expected
        :param bad_sch: pass an uninstantiated or non-schema object
        :param bad_uni: whether bad unicode is expected
        :param force_json: whether to try json if no schema is found
        :param json_err: whether a JSON error is expected
        :param exp_ret: expected return if no errors are raised
        """
        mw = mid.Marshmallow()

        mw._force_json = force_json
        if schema:
            if bad_sch:
                mw._get_schema = lambda *x, **y: self.FooSchema
            else:
                mw._get_schema = lambda *x, **y: self.FooSchema()
        else:
            mw._get_schema = lambda *x, **y: None

        req = mock.Mock(method='GET')
        if not bad_uni:
            req.stream.read.return_value = stream.encode()
        else:
            req.stream.read.return_value = stream.encode() + b'\xe7'
        req.context = {}

        if schema_err:
            with pytest.raises(errors.HTTPUnprocessableEntity):
                # noinspection PyTypeChecker
                mw.process_resource(req, 'foo', 'foo', 'foo')
            return
        if bad_uni:
            with pytest.raises(errors.HTTPBadRequest):
                # noinspection PyTypeChecker
                mw.process_resource(req, 'foo', 'foo', 'foo')
            return
        if bad_sch:
            with pytest.raises(TypeError):
                # noinspection PyTypeChecker
                mw.process_resource(req, 'foo', 'foo', 'foo')
            return
        if json_err:
            with pytest.raises(errors.HTTPBadRequest):
                # noinspection PyTypeChecker
                mw.process_resource(req, 'foo', 'foo', 'foo')
            return

        # noinspection PyTypeChecker
        mw.process_resource(req, 'foo', 'foo', 'foo')
        if schema or force_json:
            assert req.context[mw._req_key] == exp_ret
        else:
            assert mw._req_key not in req.context

    @pytest.mark.parametrize(
        'res, schema, sch_err, bad_sch, force_json, json_err, exp_ret', [
            (  # Good result, good schema
                {'bar': 'test'},
                True,
                False,
                False,
                False,
                False,
                '{"foo": "test"}'
            ),
            (  # Schema error on loading result
                {'bar': 'test', 'int': 'foo'},
                True,
                True,
                False,
                False,
                False,
                '{"foo": "test"}'
            ),
            (  # Bad schema instance (not an instance)
                {'bar': 'test'},
                True,
                False,
                True,
                False,
                False,
                '{"foo": "test"}'
            ),
            (  # Good result, no schema, force json
                {'bar': 'test'},
                False,
                False,
                False,
                True,
                False,
                '{"bar": "test"}'
            ),
            (  # Unserializable response, no schema, force json
                set('foo'),
                False,
                False,
                False,
                True,
                True,
                '{"bar": "test"}'
            ),
            (  # No schema, no force json
                {'bar': 'test'},
                False,
                False,
                False,
                False,
                False,
                '{"foo": "test"}'
            ),
            (  # No result
                None,
                True,
                False,
                False,
                False,
                False,
                '{"foo": "test"}'
            ),
        ]
    )
    def test_process_response(self, res, schema, sch_err, bad_sch, force_json,
                              json_err, exp_ret):
        """Test process_response

        :param res: the value to put in the result key on req.context
        :param schema: whether a schema should be available
        :param sch_err: whether an error is expected dumping the data
        :param bad_sch: pass an uninstantiated or non-schema object
        :param force_json: whether force_json is true
        :param json_err: whether an error is expected dumping the data
        :param exp_ret: expected return if no errors are raised
        """
        mw = mid.Marshmallow()

        mw._force_json = force_json
        if schema:
            if bad_sch:
                mw._get_schema = lambda *x, **y: self.FooSchema
            else:
                mw._get_schema = lambda *x, **y: self.FooSchema()
        else:
            mw._get_schema = lambda *x, **y: None

        req = mock.Mock(method='GET')
        if res is None:
            req.context = {}
        else:
            req.context = {mw._resp_key: res}

        resp = mock.Mock()

        if bad_sch:
            with pytest.raises(TypeError):
                # noinspection PyTypeChecker
                mw.process_response(req, resp, 'foo', 'foo')
            return
        if sch_err:
            with pytest.raises(errors.HTTPInternalServerError):
                # noinspection PyTypeChecker
                mw.process_response(req, resp, 'foo', 'foo')
            return
        if json_err:
            with pytest.raises(errors.HTTPInternalServerError):
                # noinspection PyTypeChecker
                mw.process_response(req, resp, 'foo', 'foo')
            return

        # noinspection PyTypeChecker
        mw.process_response(req, resp, 'foo', 'foo')
        if res is None or (not schema and not force_json):
            # "body" has not been written, and is thus a mock object still
            assert isinstance(resp.body, mock.Mock)
        else:
            assert resp.body == exp_ret
コード例 #10
0
class TestMarshmallow:
    """Test Marshmallow middleware"""

    mw = mid.Marshmallow()

    class FooSchema(Schema):
        """Convert foo to bar for testing purposes"""

        if MARSHMALLOW_2:
            bar = fields.String(load_from="foo", dump_to="foo")
        else:
            bar = fields.String(data_key="foo")
        int = fields.Integer()

    def test_instantiation(self):
        """Test instantiating the class"""
        mid.Marshmallow()

    @pytest.mark.parametrize(
        "method, attr_name, has_sch",
        [
            ("GET", "get_schema", True),
            ("get", "get_schema", True),
            ("get", "get_response_schema", False),
            ("get", "get_request_schema", True),
            ("get", "schema", False),
            ("get", "put_schema", False),
            ("POST", "post_schema", True),
            ("post", "post_schema", True),
            ("POST", "schema", False),
            ("POST", "get_schema", False),
            ("post", "post_response_schema", False),
            ("post", "post_request_schema", True),
            ("PATCH", "patch_schema", True),
            ("patch", "patch_schema", True),
            ("PUT", "put_schema", True),
            ("put", "put_schema", True),
            ("DELETE", "delete_schema", True),
            ("delete", "delete_schema", True),
        ],
    )
    def test_get_specific_schema(self, method, attr_name, has_sch):
        # type: (str, str, bool) -> None
        """Test getting a specific schema from a resource"""
        class TestResource:
            """Quick test object"""
            def __init__(self):
                setattr(self, attr_name, "foo")

        tr = TestResource()

        sch = mid.Marshmallow._get_specific_schema(tr, method, "request")

        if has_sch:
            assert sch == "foo"

        else:
            assert sch is None

    @pytest.mark.parametrize(
        "method, attrs, exp_value",
        [
            ("GET", (("get_schema", "foo"), ("schema", "bar")), "foo"),
            (
                "GET",
                (
                    ("get_schema", "foo"),
                    ("schema", "bar"),
                    ("post_schema", "baz"),
                ),
                "foo",
            ),
            (
                "GET",
                (
                    ("get_schema", "foo"),
                    ("get_response_schema", "bar"),
                    ("get_request_schema", "boo"),
                    ("post_response_schema", "baz"),
                ),
                "bar",
            ),
            ("GET", (("post_schema", "foo"), ("schema", "bar")), "bar"),
            ("GET", (("schema", "bar"), ), "bar"),
            ("GET", (), None),
        ],
    )
    def test_get_schema(self, method, attrs, exp_value):
        # type: (str, tuple, str) -> None
        """Test getting a general or specific schema"""
        class TestResource:
            """Quick test object"""
            def __init__(self):
                for attr_name, value in attrs:
                    setattr(self, attr_name, value)

        tr = TestResource()

        val = mid.Marshmallow()._get_schema(tr, method, "response")

        if exp_value is None:
            assert val is None
        else:
            assert val == exp_value

    @pytest.mark.parametrize(
        "stream, schema, schema_err, bad_sch, force_json, json_err, "
        "exp_ret",
        [
            (  # 0: Good schema
                '{"foo": "test"}',
                True,
                False,
                False,
                False,
                False,
                {
                    "bar": "test"
                },
            ),
            (  # 1: Schema errors on load
                '{"foo": "test", "int": "test"}',
                True,
                True,
                False,
                False,
                False,
                {
                    "bar": "test"
                },
            ),
            (  # 2: Good schema, bad unicode in body
                '{"foo": "testé"}',
                True,
                False,
                False,
                False,
                False,
                {
                    "bar": "testé"
                },
            ),
            (  # 3: Bad schema
                '{"foo": "test"}',
                True,
                False,
                True,
                False,
                False,
                {
                    "bar": "test"
                },
            ),
            (  # 4: No schema, no force json (no change to req.context)
                '{"foo": "test"}',
                False,
                False,
                False,
                False,
                False,
                {
                    "bar": "test"
                },
            ),
            (  # 5: No schema, force json
                '{"foo": "test"}',
                False,
                False,
                False,
                True,
                False,
                {
                    "foo": "test"
                },
            ),
            (  # 6: No schema, force json, bad json
                '{"foo": }',
                False,
                False,
                False,
                True,
                True,
                {
                    "foo": "test"
                },
            ),
            (  # 7: No schema, force json, good json, bad unicode
                '{"foo": "testé"}',
                False,
                False,
                False,
                True,
                False,
                {
                    "foo": "testé"
                },
            ),
        ],
    )
    def test_process_resource(self, stream, schema, schema_err, bad_sch,
                              force_json, json_err, exp_ret):
        # type: (str, bool, bool, bool, bool, bool, dict) -> None
        """Test processing a resource

        :param stream: the return of req.bounded_stream.read()
        :param schema: whether a schema should be returned (TestSchema)
        :param schema_err: whether a schema error is expected
        :param bad_sch: pass an uninstantiated or non-schema object
        :param force_json: whether to try json if no schema is found
        :param json_err: whether a JSON error is expected
        :param exp_ret: expected return if no errors are raised
        """
        mw = mid.Marshmallow()

        mw._force_json = force_json
        if schema:
            if bad_sch:
                setattr(mw, "_get_schema", lambda *_, **__: self.FooSchema)
            else:
                setattr(mw, "_get_schema", lambda *_, **__: self.FooSchema())
        else:
            setattr(mw, "_get_schema", lambda *_, **__: None)

        req = mock.Mock(method="GET")
        req.bounded_stream.read.return_value = stream
        req.context = {}

        if schema_err:
            with pytest.raises(errors.HTTPUnprocessableEntity):
                mw.process_resource(req, "foo", "foo", "foo")  # type: ignore
            return
        if bad_sch:
            with pytest.raises(TypeError):
                mw.process_resource(req, "foo", "foo", "foo")  # type: ignore
            return
        if json_err:
            with pytest.raises(errors.HTTPBadRequest):
                mw.process_resource(req, "foo", "foo", "foo")  # type: ignore
            return

        mw.process_resource(req, "foo", "foo", "foo")  # type: ignore
        if schema or force_json:
            assert req.context[mw._req_key] == exp_ret
        else:
            assert mw._req_key not in req.context

    @pytest.mark.parametrize(
        "res, schema, sch_err, bad_sch, force_json, json_err, exp_ret",
        [
            (  # 0: Good result, good schema
                {
                    "bar": "test"
                },
                True,
                False,
                False,
                False,
                False,
                '{"foo": "test"}',
            ),
            (  # 1: Schema error on loading result
                {
                    "bar": "test",
                    "int": "foo"
                },
                True,
                True,
                False,
                False,
                False,
                '{"foo": "test"}',
            ),
            (  # 2: Bad schema instance (not an instance)
                {
                    "bar": "test"
                },
                True,
                False,
                True,
                False,
                False,
                '{"foo": "test"}',
            ),
            (  # 3: Good result, no schema, force json
                {
                    "bar": "test"
                },
                False,
                False,
                False,
                True,
                False,
                '{"bar": "test"}',
            ),
            (  # 4: Unserializable response, no schema, force json
                set("foo"),
                False,
                False,
                False,
                True,
                True,
                '{"bar": "test"}',
            ),
            (  # 5: No schema, no force json
                {
                    "bar": "test"
                },
                False,
                False,
                False,
                False,
                False,
                '{"foo": "test"}',
            ),
            (  # 6: No result
                None,
                True,
                False,
                False,
                False,
                False,
                '{"foo": "test"}',
            ),
        ],
    )
    def test_process_response(self, res, schema, sch_err, bad_sch, force_json,
                              json_err, exp_ret):
        """Test process_response

        :param res: the value to put in the result key on req.context
        :param schema: whether a schema should be available
        :param sch_err: whether an error is expected dumping the data
        :param bad_sch: pass an uninstantiated or non-schema object
        :param force_json: whether force_json is true
        :param json_err: whether an error is expected dumping the data
        :param exp_ret: expected return if no errors are raised
        """
        mw = mid.Marshmallow()

        mw._force_json = force_json
        if schema:
            if bad_sch:
                setattr(mw, "_get_schema", lambda *_, **__: self.FooSchema)
            else:
                setattr(mw, "_get_schema", lambda *_, **__: self.FooSchema())
        else:
            setattr(mw, "_get_schema", lambda *_, **__: None)

        req = mock.Mock(method="GET")
        if res is None:
            req.context = {}
        else:
            req.context = {mw._resp_key: res}

        resp = mock.Mock()

        if bad_sch:
            with pytest.raises(TypeError):
                mw.process_response(req, resp, "foo", "foo")  # type: ignore
            return
        if sch_err:
            with pytest.raises(errors.HTTPInternalServerError):
                mw.process_response(req, resp, "foo", "foo")  # type: ignore
            return
        if json_err:
            with pytest.raises(errors.HTTPInternalServerError):
                mw.process_response(req, resp, "foo", "foo")  # type: ignore
            return

        mw.process_response(req, resp, "foo", "foo")  # type: ignore
        if res is None or (not schema and not force_json):
            # "body" has not been written, and is thus a mock object still
            assert isinstance(resp.body, mock.Mock)
        else:
            assert resp.body == exp_ret