Testing SAP integrations

Mock SAP connections and entity results in tests that run without a real SAP system.

When a service reads business partners from S/4HANA or employees from SuccessFactors, its logic needs tests that run without a real backend. This page shows how to mock SAP responses so tests run fast and require no access to the actual systems.

Note: If you're new to unit testing with Zato, check the tutorial first.

Basic usage

Services access SAP connections like this:

from zato.server.service import Service

class GetPartnersByCity(Service):
    name = 'sap.partners.by-city'
    input = 'city'

    def handle(self):
        conn = self.sap['SAP.Sample']
        partners = conn.read('A_BusinessPartner',
            filter=f"CityName eq '{self.request.input.city}'",
            orderby='BusinessPartnerName',
        )

        items = []
        for partner in partners:
            items.append({'name': partner['BusinessPartnerName'], 'city': partner['CityName']})

        self.response.payload = {'partners': items}

Mock the SAP results in your test:

from zato_testing import ServiceTestCase
from myapp.services import GetPartnersByCity

class TestGetPartnersByCity(ServiceTestCase):

    def test_returns_partners(self):

        # Configure SAP results with the sap: prefix
        self.set_response('sap:SAP.Sample', [
            {'BusinessPartner': '1000001', 'BusinessPartnerName': 'Adatum Corporation', 'CityName': 'London'},
            {'BusinessPartner': '1000002', 'BusinessPartnerName': 'Trey Research', 'CityName': 'London'},
        ])

        service = self.invoke(GetPartnersByCity, city='London')

        self.assertEqual(len(service.response.payload['partners']), 2)
        self.assertEqual(service.response.payload['partners'][0]['name'], 'Adatum Corporation')

Note the sap: prefix to distinguish SAP connections from REST connections.

Single entities

Services that read one entity by key use .get - mock a single dict:

class GetPartner(Service):
    name = 'sap.partner.get'
    input = 'partner_id'

    def handle(self):
        conn = self.sap['SAP.Sample']
        partner = conn.get('A_BusinessPartner', self.request.input.partner_id)

        self.response.payload = {'name': partner['BusinessPartnerName']}
class TestGetPartner(ServiceTestCase):

    def test_returns_partner(self):

        self.set_response('sap:SAP.Sample', {
            'BusinessPartner': '1000001', 'BusinessPartnerName': 'Adatum Corporation', 'CityName': 'London'
        })

        service = self.invoke(GetPartner, partner_id='1000001')

        self.assertEqual(service.response.payload['name'], 'Adatum Corporation')

Empty results

Test handling of entities not found:

class TestNoPartners(ServiceTestCase):

    def test_handles_empty_set(self):

        self.set_response('sap:SAP.Sample', [])

        service = self.invoke(GetPartnersByCity, city='Atlantis')

        self.assertEqual(service.response.payload['partners'], [])

Adapters

Services built on SAPAdapter are tested the same way - the mocked results are what self._invoke_odata() returns:

from zato.server.service import SAPAdapter

class PartnersByCity(SAPAdapter):
    name = 'sap.adapter.partners-by-city'

    conn_name  = 'SAP.Sample'
    entity_set = 'A_BusinessPartner'
    filter     = "CityName eq '{city}'"

    def handle(self):
        items = self._invoke_odata()
        self.response.payload = {'items': items}
class TestPartnersByCity(ServiceTestCase):

    def test_maps_items(self):

        self.set_response('sap:SAP.Sample', [
            {'BusinessPartner': '1000001', 'BusinessPartnerName': 'Adatum Corporation', 'CityName': 'London'},
        ])

        service = self.invoke(PartnersByCity, city='London')

        self.assertEqual(len(service.response.payload['items']), 1)

Live testing with the OData test server

Beyond unit tests, Zato ships with an in-process OData test server that speaks both V2 and V4 and simulates the auth and validation behavior of S/4HANA and SuccessFactors - including CSRF token exchanges, OAuth2 token endpoints and server-driven paging. It records every request it receives, which lets integration tests assert both the mapped output and what actually went over the wire.

Learn more