Show TOC

Step 2: Creating a Mock Server to Simulate DataLocate this document in the navigation structure

In this step we use the mock server to add data to our app without dependency to any remote server or system.

Preview
Figure 1: The app now contains data
Coding

You can view and download all files in the Explored app in the Demo Kit under Mock Server - Step 2.

webapp/test/mockServer.html
<!DOCTYPE HTML>
<html>
	<head>
		<meta http-equiv="X-UA-Compatible" content="IE=edge">
		<meta charset="utf-8">
		<title>MockServerTutorial</title>
		<script id="sap-ui-bootstrap"
			src="../../resources/sap-ui-core.js"
			data-sap-ui-libs="sap.m"
			data-sap-ui-theme="sap_bluecrystal"
			data-sap-ui-xx-bindingSyntax="complex"
			data-sap-ui-resourceroots='{"sap.ui.demo.MockServer": "../"}'>
		</script>
		<link rel="stylesheet" type="text/css" href="../css/style.css">
		<script>
			sap.ui.getCore().attachInit(function() {
				sap.ui.require([
					"sap/ui/demo/MockServer/localService/mockserver",
					"sap/m/Shell",
					"sap/ui/core/ComponentContainer"
				], function (mockserver, Shell, ComponentContainer) {
					mockserver.init();
					new Shell({
						app: new sap.ui.core.ComponentContainer({
							height : "100%",
							name : "MockServerTutorial"
						})
					}).placeAt("content");
				});
			});
		</script>
	</head>
	<body class="sapUiBody" id="content">
	</body>
</html>

We use this file to run our app in test mode with mock data. We use the sap.ui.require syntax, because we load more additional files required for the start of our app. The first dependency is a file called mockserver.js that is located in the webapp/localService folder. The Shell and the ComponentContainer controls are also loaded as a dependency by the require statement.

The new artifact that we just loaded and are about to implement is our local mock server that is immediately called with init method before we actually instantiate the component. By doing so, we can catch all requests that would go to the “real” service and process it locally by our mock server when launching the app with the webapp/test/mockServer.html file.
Note

A productive application does not contain the mock server code and thus connects to the real service instead. The HTML page above is defined only for local testing and to be called in automated tests. The application coding itself is unchanged and does not know the difference between the real and the mocked back-end service.

webapp/localService/metadata.xml
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<edmx:Edmx Version="1.0"
    xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx">
    <edmx:DataServices
        xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" m:DataServiceVersion="1.0">
        <Schema Namespace="NerdMeetup.Models"
            xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
            xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
            xmlns="http://schemas.microsoft.com/ado/2006/04/edm">
            <EntityType Name="Meetup">
                <Key>
                    <PropertyRef Name="MeetupID" />
                </Key>
                <Property Name="MeetupID" Type="Edm.Int32" Nullable="false" />
                <Property Name="Title" Type="Edm.String" Nullable="true" />
                <Property Name="EventDate" Type="Edm.DateTime" Nullable="false" />
                <Property Name="Description" Type="Edm.String" Nullable="true" />
                <Property Name="HostedBy" Type="Edm.String" Nullable="true" />
                <Property Name="ContactPhone" Type="Edm.String" Nullable="true" />
                <Property Name="Address" Type="Edm.String" Nullable="true" />
                <Property Name="Country" Type="Edm.String" Nullable="true" />
                <Property Name="Latitude" Type="Edm.Double" Nullable="false" />
                <Property Name="Longitude" Type="Edm.Double" Nullable="false" />
                <Property Name="HostedById" Type="Edm.String" Nullable="true" />
                <Property Name="Location" Type="NerdMeetup.Models.LocationDetail" Nullable="false" />
            </EntityType>
            <ComplexType Name="LocationDetail" />
            <EntityContainer Name="NerdMeetups" m:IsDefaultEntityContainer="true">
                <EntitySet Name="Meetups" EntityType="NerdMeetup.Models.Meetup" />
                <FunctionImport Name="FindUpcomingMeetups" EntitySet="Meetups" ReturnType="Collection(NerdMeetup.Models.Meetup)" m:HttpMethod="GET" />
            </EntityContainer>
        </Schema>
    </edmx:DataServices>
</edmx:Edmx>

The metadata file contains information about the service interface and does not need to be written manually. It defines a Meetup entity, a Meetups entity set and a function import definition.

webapp/localService/mockdata/Meetups.json (New)
[{
	"MeetupID": 1,
	"Title": "Toronto Tech Meet-Up",
	"EventDate": "/Date(1278450000000)/",
	"Description": "The best way to expand your knowledge and network of the Toronto technology community"
}, {
	"MeetupID": 2,
	"Title": "Los Angeles Redditors",
	"EventDate": "/Date(1478171994000)/",
	"Description": "This is a meet-up group specifically for redditors of r/LosAngeles. If you don't know what that is, this isn't the meet-up you're looking for"
}, {
	"MeetupID": 3,
	"Title": "Designers + Geeks New York",
	"EventDate": "/Date(1070968794000)/",
	"Description": "Bringing designers + geeks together to talk shop, start-ups, and do some knowledge sharing. All types of designers + geeks welcome"
}, {
	"MeetupID": 4,
	"Title": "New York City Geek Adventure Group",
	"EventDate": "/Date(1034763594000)/",
	"Description": "Are you looking to have fun and go on random adventures?"
}]

The Meetups.json file is automatically read by the mock server later in this step. It represents a flat array of Meetup items.

webapp/localService/mockserver.js (New)
sap.ui.define([
	"sap/ui/core/util/MockServer"
], function(MockServer) {
	"use strict";
	return {
		/**
		 * Initializes the mock server.
		 * You can configure the delay with the URL parameter "serverDelay".
		 * The local mock data in this folder is returned instead of the real data for testing.
		 * @public
		 */
		init: function() {
			// create
			var oMockServer = new MockServer({
				rootUri: "/"
			});
			// simulate against the metadata and mock data
			oMockServer.simulate("../localService/metadata.xml", {
				sMockdataBaseUrl: "../localService/mockdata",
				bGenerateMissingMockData: true
			});
			// start
			oMockServer.start();
			jQuery.sap.log.info("Running the app with mock data");
		}
	};
});

Now we can write the code to initialize the mock server that will simulate the requests instead of the real server. We load the MockServer module as a dependency and create a helper object that defines an init method to start the server. This method is called before the Component initialization in the mockServer.html file above. The init method creates a MockServer instance with the same URL as the real service. The URL in configuration parameter rootURI is now served by our test server instead of the real service.

Next, we set two global configuration settings for all MockServer instances that tell the server to respond automatically and introduce a delay of one second to imitate a typical server response time.

In order to simulate a manual back-end call we can simply call the simulate method on the MockServer instance with the path to our newly created metadata.xml file. This will read the test data from our local file system and set up the URL patterns that will mimic the real service. The first parameter is the path to the service metadata.xml document. The second parameter is an object with the following properties:
  • sMockdataBaseUrl: path where to look for mock data files in JSON format

  • bGenerateMissingMockData: Boolean property to tell the MockServer to use auto-generated mock data in case no JSON files are found.

We call the function start on the mock server instance. From this point on, each request matching the URL pattern rootURI will be processed by the MockServer.

Finally, we add a message toast to indicate for the user that the app runs with mock data.

This approach is perfect for local and automated testing, even without any network connection. Your development does not depend on the availability of a remote server, i.e. to run your tests independently from the back-end service. You can control the mocked data so the requests will return reliable and predictable results.

If the real service connection cannot be established, for example, when there is no network connection, you can always fall back to the local test page and run the app with mock data.

Just run the app now again with the mockServer.html file.. The list should now be populated with meet-ups from our mock data. You can also choose the button and see data.