Mock Server configuration in SAP UI5 Application.
2024-1-9 17:45:41 Author: blogs.sap.com(查看原文) 阅读量:13 收藏

Hello everyone, 

In this blog post I’m going to explain the mock server configuration in SAP UI5 Application in detail and simple steps. 

Overview: 

So, in simple words mock server is a dummy server which is used test our application at the application layer itself. 

for developing and testing our application we can make use of the mock server and by this we can avoid the additional load on the system, because the mock server will be present in the application layer itself so that fetching the data is easy for the system. 

So, the mock server serves the local files and mimics the real back-end service more realistically. 

So, here I have created one project named project4 and used odata service to load the real data  and also used mockservice to load the mock data. So if we run the application by Index.html it will load the real data from the odata service and if we run the application by mockserver.html then it will load the dummy data from json files present in the mockdata folder.

odata service used : https://services.odata.org/V2/Northwind/Northwind.svc/

Folder Structure:  

So, there are two folder we need for placing the files required for mock server configuration namely localService folder and test folder as below. 

Folder%20Structure.

Folder Structure.

Step 1: Create mockserver.html file 

First, we have to create localservice  and test server folder as shown in the above picture. 

So in the test folder we have to create the mockserver.html file. 

It’s similar to Index.html file, in this file we give the path for the initmockserver file as below. 

from now we will be having two entry points for our application to run one is Index.html and another one is mockserver.html file. 

mockserver.html   

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Mock Server Tutorial</title>
	<script id="sap-ui-bootstrap"
		src="https://sapui5.hana.ondemand.com/resources/sap-ui-core.js"
		data-sap-ui-theme="sap_belize"
		data-sap-ui-resourceroots='{
			"project4": "../"
		}'
		data-sap-ui-oninit="module:project4/test/initMockServer"
		data-sap-ui-compatVersion="edge"
		data-sap-ui-async="true">
	</script>
</head>
<body class="sapUiBody">
	<div data-sap-ui-component data-name="project4" data-id="container" data-settings='{"id" : "MockServer"}'></div>
</body>
</html>

From the Index.html we could run our real service and from the mockserver.html we could run our mock data. Its just a copy of the Index.html file and here we change the title of the page to distinguish from the Index.html file. 

So, in the above code we can see path given for the initmockserver file and this mockserver.html file is the new entry point for running our application in test mode with mock data loaded from the JSON files. 

step 2:  Create initMockServer.js file 

So now we have to create another file named initMockServer.js in the test folder. we should not place the test pages in the application root folder but we can put in the subfolder named test to clearly separate the productive and test coding so that we can reduce the complexity to understand. 

odata service used : https://services.odata.org/V2/Northwind/Northwind.svc/

InitMockServer.js 

sap.ui.define([
	"project4/localService/mockServer"
], function (mockserver) {
	"use strict";
    debugger
	// initialize the mock server
	
	mockserver.init();

	// initialize the embedded component on the HTML page
	sap.ui.require(["sap/ui/core/ComponentSupport"]);
});

as we see in the above code, here we are adding the dependency for the mockerver.js file which is present in the localService folder. 

So here we can see in the above code we called the init method of the mockserver.js file located in the localService folder before the loading of the component. So, this is how we can take all the requests that would go to the real service and process them locally by our test server when launching the app with the mockserver.html file. So, in the mockserver.js file we will giving the our mock data paths so for that first we need to create the mockdata folder in the localService folder and insert the json files into that folder and we have to create the metadata file and then path should be specified in the mockserver.js and manifest files that we will see now. 

so, the folder structure should be as shown in the above folder structure picture. now let’s create metadata file. So I have used odata service so if we write $metadata in the browser after service url we get metadata as shown in the below figure. So just save the file and import it to the localService folder by drag and drop.

loading%20metadata%20in%20browser

loading metadata in browser

So metadata file will be added to the localService folder. Here just for easy understanding I have removed all the entitysets and entytytypes except Orders.

So keeping only one entity set that is Orders and using that in the application.

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="NorthwindModel" 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/2008/09/edm">
    
      <EntityType Name="Order">
        <Key>
          <PropertyRef Name="OrderID" />
        </Key>
        <Property Name="OrderID" Type="Edm.Int32" Nullable="false" p8:StoreGeneratedPattern="Identity" xmlns:p8="http://schemas.microsoft.com/ado/2009/02/edm/annotation" />
        <Property Name="CustomerID" Type="Edm.String" Nullable="true" MaxLength="5" Unicode="true" FixedLength="true" />
        <Property Name="EmployeeID" Type="Edm.Int32" Nullable="true" />
        <Property Name="OrderDate" Type="Edm.DateTime" Nullable="true" />
        <Property Name="RequiredDate" Type="Edm.DateTime" Nullable="true" />
        <Property Name="ShippedDate" Type="Edm.DateTime" Nullable="true" />
        <Property Name="ShipVia" Type="Edm.Int32" Nullable="true" />
        <Property Name="Freight" Type="Edm.Decimal" Nullable="true" Precision="19" Scale="4" />
        <Property Name="ShipName" Type="Edm.String" Nullable="true" MaxLength="40" Unicode="true" FixedLength="false" />
        <Property Name="ShipAddress" Type="Edm.String" Nullable="true" MaxLength="60" Unicode="true" FixedLength="false" />
        <Property Name="ShipCity" Type="Edm.String" Nullable="true" MaxLength="15" Unicode="true" FixedLength="false" />
        <Property Name="ShipRegion" Type="Edm.String" Nullable="true" MaxLength="15" Unicode="true" FixedLength="false" />
        <Property Name="ShipPostalCode" Type="Edm.String" Nullable="true" MaxLength="10" Unicode="true" FixedLength="false" />
        <Property Name="ShipCountry" Type="Edm.String" Nullable="true" MaxLength="15" Unicode="true" FixedLength="false" />
        <NavigationProperty Name="Customer" Relationship="NorthwindModel.FK_Orders_Customers" FromRole="Orders" ToRole="Customers" />
        <NavigationProperty Name="Employee" Relationship="NorthwindModel.FK_Orders_Employees" FromRole="Orders" ToRole="Employees" />
        <NavigationProperty Name="Order_Details" Relationship="NorthwindModel.FK_Order_Details_Orders" FromRole="Orders" ToRole="Order_Details" />
        <NavigationProperty Name="Shipper" Relationship="NorthwindModel.FK_Orders_Shippers" FromRole="Orders" ToRole="Shippers" />
      </EntityType>
      
    </Schema>
    <Schema Namespace="ODataWeb.Northwind.Model" 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/2008/09/edm">
      <EntityContainer Name="NorthwindEntities" p7:LazyLoadingEnabled="true" m:IsDefaultEntityContainer="true" xmlns:p7="http://schemas.microsoft.com/ado/2009/02/edm/annotation">
       
        <EntitySet Name="Orders" EntityType="NorthwindModel.Order" />
      
       
      </EntityContainer>
    </Schema>
  </edmx:DataServices>
</edmx:Edmx>

So in the metadata file we will be having number of entity sets in the enititySet Container and entitytype name will be there so in the respective entity type of the entityset number of properties will be present. So now we will create the json file in the mockdata folder. 

Note: The json file which we are going create should be same name as the respective EntitySet name which we have given in the metadata file. So, this builds the link between the metadata and json mock data. And also, you must write the enity type name and add the required properties in to the entity type as shown in above code. if you won’t write the entity type and required properties it will load only last object of the json file. 

Here I have used the Orders EntitySet. So we can copy the data from real service by writing

EnitySetName?$format=json    after the service url in the browser we can load the data in the json format as shown in the below figure.

loading%20the%20data%20in%20json%20format

loading the data in json format

So just save the file from the browser and and import it to the mockdata folder present in the localService folder by drag and drop.

so in the json file lot of data will be present so just remove some data so that we get to know application is loading the mockdata when we run our application by using the mockserver.html.

Orders.json

{
"d" : {
"results": [
  {
"__metadata": {
"uri": "https://services.odata.org/V2/Northwind/Northwind.svc/Orders(10443)", "type": "NorthwindModel.Order"
}, "OrderID": 10443, "CustomerID": "REGGC", "EmployeeID": 8, "OrderDate": "\/Date(855705600000)\/", "RequiredDate": "\/Date(858124800000)\/", "ShippedDate": "\/Date(855878400000)\/", "ShipVia": 1, "Freight": "13.9500", "ShipName": "Reggiani Caseifici", "ShipAddress": "Strada Provinciale 124", "ShipCity": "Reggio Emilia", "ShipRegion": null, "ShipPostalCode": "42100", "ShipCountry": "Italy", "Customer": {
"__deferred": {
"uri": "https://services.odata.org/V2/Northwind/Northwind.svc/Orders(10443)/Customer"
}
}, "Employee": {
"__deferred": {
"uri": "https://services.odata.org/V2/Northwind/Northwind.svc/Orders(10443)/Employee"
}
}, "Order_Details": {
"__deferred": {
"uri": "https://services.odata.org/V2/Northwind/Northwind.svc/Orders(10443)/Order_Details"
}
}, "Shipper": {
"__deferred": {
"uri": "https://services.odata.org/V2/Northwind/Northwind.svc/Orders(10443)/Shipper"
}
}
}, {
"__metadata": {
"uri": "https://services.odata.org/V2/Northwind/Northwind.svc/Orders(10444)", "type": "NorthwindModel.Order"
}, "OrderID": 10444, "CustomerID": "BERGS", "EmployeeID": 3, "OrderDate": "\/Date(855705600000)\/", "RequiredDate": "\/Date(858124800000)\/", "ShippedDate": "\/Date(856483200000)\/", "ShipVia": 3, "Freight": "3.5000", "ShipName": "Berglunds snabbk\u00f6p", "ShipAddress": "Berguvsv\u00e4gen  8", "ShipCity": "Lule\u00e5", "ShipRegion": null, "ShipPostalCode": "S-958 22", "ShipCountry": "Sweden", "Customer": {
"__deferred": {
"uri": "https://services.odata.org/V2/Northwind/Northwind.svc/Orders(10444)/Customer"
}
}, "Employee": {
"__deferred": {
"uri": "https://services.odata.org/V2/Northwind/Northwind.svc/Orders(10444)/Employee"
}
}, "Order_Details": {
"__deferred": {
"uri": "https://services.odata.org/V2/Northwind/Northwind.svc/Orders(10444)/Order_Details"
}
}, "Shipper": {
"__deferred": {
"uri": "https://services.odata.org/V2/Northwind/Northwind.svc/Orders(10444)/Shipper"
}
}
}, {
"__metadata": {
"uri": "https://services.odata.org/V2/Northwind/Northwind.svc/Orders(10445)", "type": "NorthwindModel.Order"
}, "OrderID": 10445, "CustomerID": "BERGS", "EmployeeID": 3, "OrderDate": "\/Date(855792000000)\/", "RequiredDate": "\/Date(858211200000)\/", "ShippedDate": "\/Date(856396800000)\/", "ShipVia": 1, "Freight": "9.3000", "ShipName": "Berglunds snabbk\u00f6p", "ShipAddress": "Berguvsv\u00e4gen  8", "ShipCity": "Lule\u00e5", "ShipRegion": null, "ShipPostalCode": "S-958 22", "ShipCountry": "Sweden", "Customer": {
"__deferred": {
"uri": "https://services.odata.org/V2/Northwind/Northwind.svc/Orders(10445)/Customer"
}
}, "Employee": {
"__deferred": {
"uri": "https://services.odata.org/V2/Northwind/Northwind.svc/Orders(10445)/Employee"
}
}, "Order_Details": {
"__deferred": {
"uri": "https://services.odata.org/V2/Northwind/Northwind.svc/Orders(10445)/Order_Details"
}
}, "Shipper": {
"__deferred": {
"uri": "https://services.odata.org/V2/Northwind/Northwind.svc/Orders(10445)/Shipper"
}
}
}, {
"__metadata": {
"uri": "https://services.odata.org/V2/Northwind/Northwind.svc/Orders(10446)", "type": "NorthwindModel.Order"
}, "OrderID": 10446, "CustomerID": "TOMSP", "EmployeeID": 6, "OrderDate": "\/Date(855878400000)\/", "RequiredDate": "\/Date(858297600000)\/", "ShippedDate": "\/Date(856310400000)\/", "ShipVia": 1, "Freight": "14.6800", "ShipName": "Toms Spezialit\u00e4ten", "ShipAddress": "Luisenstr. 48", "ShipCity": "M\u00fcnster", "ShipRegion": null, "ShipPostalCode": "44087", "ShipCountry": "Germany", "Customer": {
"__deferred": {
"uri": "https://services.odata.org/V2/Northwind/Northwind.svc/Orders(10446)/Customer"
}
}, "Employee": {
"__deferred": {
"uri": "https://services.odata.org/V2/Northwind/Northwind.svc/Orders(10446)/Employee"
}
}, "Order_Details": {
"__deferred": {
"uri": "https://services.odata.org/V2/Northwind/Northwind.svc/Orders(10446)/Order_Details"
}
}, "Shipper": {
"__deferred": {
"uri": "https://services.odata.org/V2/Northwind/Northwind.svc/Orders(10446)/Shipper"
}
}
}, {
"__metadata": {
"uri": "https://services.odata.org/V2/Northwind/Northwind.svc/Orders(10447)", "type": "NorthwindModel.Order"
}, "OrderID": 10447, "CustomerID": "RICAR", "EmployeeID": 4, "OrderDate": "\/Date(855878400000)\/", "RequiredDate": "\/Date(858297600000)\/", "ShippedDate": "\/Date(857692800000)\/", "ShipVia": 2, "Freight": "68.6600", "ShipName": "Ricardo Adocicados", "ShipAddress": "Av. Copacabana, 267", "ShipCity": "Rio de Janeiro", "ShipRegion": "RJ", "ShipPostalCode": "02389-890", "ShipCountry": "Brazil", "Customer": {
"__deferred": {
"uri": "https://services.odata.org/V2/Northwind/Northwind.svc/Orders(10447)/Customer"
}
}, "Employee": {
"__deferred": {
"uri": "https://services.odata.org/V2/Northwind/Northwind.svc/Orders(10447)/Employee"
}
}, "Order_Details": {
"__deferred": {
"uri": "https://services.odata.org/V2/Northwind/Northwind.svc/Orders(10447)/Order_Details"
}
}, "Shipper": {
"__deferred": {
"uri": "https://services.odata.org/V2/Northwind/Northwind.svc/Orders(10447)/Shipper"
}
}
}
], "__next": "https://services.odata.org/V2/Northwind/Northwind.svc/Orders?$skiptoken=10447"
}
}

So as per the requirement we have used the Orders entityset and created the json file with the same name in the mockdata folder.

So now we will create the mockserver.js file and will specify the path of the metadata file and mockdata folder path to simulate the service. 

mockServer.js 

sap.ui.define([
	"sap/ui/core/util/MockServer"
], (MockServer) => {
	"use strict";

	return {
		init:  function () {
			
			// create
			const oMockServer = new MockServer({
				rootUri: "/V2/Northwind/Northwind.svc/"
			});

			const oUrlParams = new URLSearchParams(window.location.search);

			// configure mock server with a delay
			MockServer.config({
				autoRespond: true,
				autoRespondAfter: oUrlParams.get("serverDelay") || 999
			});

			// simulate
            oMockServer.simulate("../localService/metadata.xml", {
				sMockdataBaseUrl: "../localService/mockdata",
				bGenerateMissingMockData: true
			});
			// const sPath = sap.ui.require.toUrl("project4/localService");
			// oMockServer.simulate(sPath + "/metadata.xml", sPath + "/mockdata");

			// start
			oMockServer.start();
		}
	};
});

So init method of this mockserver.js file will be called in the initMockServer.js file. In this file we will be creating Mock server Object and will be specifying the rootUri and the URL in the rootUri configuration parameter has to point to the same URL as defined in the uri property of the data source in the manifest.json descriptor file. And we will be giving path of the metadata.xml file and mockdata folder present in the local service folder and also we will be specifying the server delay of 999 ms to imitate the real service. 

So no need to touch the manifest.json file in this case all the data source will be there because we have used the real service and the metadata file path will also be present in the localuri section.

And in the uri of the mainservice we will be having the service uri path so same path we been specified in he mockServer.js file that is in the rooturi path so when ever app runs with mockserver.html it will read the mockserver.js file before the manifest file so when the real service called in the manifest file it will load the respective mock data present the json files of the mockdata folder present in the localService folder.

when we run our application on index.html so then it will load the as usual real service data.

service%20uri%20in%20the%20manifest.json%20file

service uri in the manifest.json file

So now create a copy of  the ui5.yaml file and put name as ui5-mock.yaml  file remove entry of  back and server from the ui-mock.yaml file. Create the new npm command in the package.json file to run the application application from the mockserver.html. So here we willbe specifying the file name ui5-mock.yaml and giving the path of the mockserver.html file present in the test folder.

entry%20of%20backend%20server%20in%20ui5-mock.yaml%20file

entry of backend server in ui5-mock.yaml file

removed%20entry%20of%20real%20service%20in%20ui5-mock.yaml%20file

removed entry of real service in ui5-mock.yaml file

So remove that entry of the real backend server and do the command configuration in the  package .json file as shown in the below picture.

package.json%20configuration

package.json configuration

So now we can use this service data from the local service by using this default model. So, for that I will create a table and by using the entity set I will bind the mock data to the table so that we can display the data in the UI. 

View1.view.xml 

<mvc:View controllerName="project4.controller.View1"
    xmlns:mvc="sap.ui.core.mvc" displayBlock="true"
    xmlns="sap.m">
    <Page id="page" title="{i18n>title}">
       <content>
	   <Button text="hello" press="onPress"></Button>
             	<Table id="_IDGenTable1" 
			items="{/Orders}">
			<headerToolbar>
				<OverflowToolbar id="_IDGenOverflowToolbar1">
					<Title id="_IDGenTitle1" text="Employee Details" level="H2"/>
					<ToolbarSpacer id="_IDGenToolbarSpacer1"/>
					<Button id="_IDGenButton1"
						tooltip="Sort"
						icon="sap-icon://sort"
						press="handleSortButtonPressed"/>
					<Button id="_IDGenButton2"
						tooltip="Filter"
						icon="sap-icon://filter"
						press="handleFilterButtonPressed"/>
					<Button id="_IDGenButton3"
						tooltip="Group"
						icon="sap-icon://group-2"
						press="handleGroupButtonPressed"/>
					<ToggleButton id="_IDGenToggleButton1" icon="sap-icon://menu" tooltip="Enable Custom Context Menu" press="onToggleContextMenu" />
				</OverflowToolbar>
			</headerToolbar>
			<infoToolbar>
				<OverflowToolbar id="vsdFilterBar" visible="false">
					<Text id="vsdFilterLabel" />
				</OverflowToolbar>
			</infoToolbar>
			<columns>
				<Column id="_IDGenColumn1"  width="12em" headerMenu="columnHeaderMenu"><Text id="_IDGenText1" text="Employee Name" /></Column>
				<Column id="_IDGenColumn2" minScreenWidth="Tablet" demandPopin="true"><Text id="_IDGenText2" text="Working City" /></Column>
				<Column id="_IDGenColumn3" minScreenWidth="Tablet" demandPopin="true" ><Text id="_IDGenText3" text="Age " /></Column>
				<Column id="_IDGenColumn4" minScreenWidth="Tablet" demandPopin="true" ><Text id="_IDGenText4" text="Designation " /></Column>
				
			</columns>
			<items>
				<ColumnListItem id="_IDGenColumnListItem1" vAlign="Middle">
					<cells>
						<ObjectIdentifier id="_IDGenObjectIdentifier1" title="{CustomerID}" text="{OrderID}" />
						<Text id="_IDGenText6" text="{ShipCity}" />
						<Text id="_IDGenText7" text="{CustomerID}" />
						<ObjectNumber id="_IDGenObjectNumber1" number="{ShipAddress}"/>
					</cells>
				</ColumnListItem>
			</items>
		</Table>
            
       </content>
    </Page>
</mvc:View>

So all setup is ready and now we can run our application by two ways one is by npm run start Command so it will read the ui5.yaml file and run application as index.html file as a entry point and load the reals service data.

Another way is by running the new command npm run start-mk which we have create in the package.json file, So this will read the ui5-mock.yaml file and start our application by the mockserver.html file as the entry point so it will load the mock data.

So lets first load our data with real server by running npm run start.

it will load the real data as shown.

data%20loaded%20from%20real%20service

data loaded from real service

now run our application by npm run start-mk command. So it will load the mock data.

                        Running app by npm run start-mk.

imitating%20the%20real%20server%20by%20showing%20busy%20symbol

imitating the real server by showing busy symbol by server delay.

loading%20the%20mockdata

loading the mockdata

Here it loading only some  records because I have removed the records from the json file and kept only some records so this is the proof that the data is loading from the mockdata folder present in the localService folder.

So this how we can test or develop our application by doing the mockService Configuration.

Flow of mock server :  

First the entry point of the application to run mockserver.html file, So in this file we have given the path of the initMockServer.js file so from this file it will call the init method of the mockServer.js file before initializing the component, so in the mockServer.js file it will simulate the real service and mockServer get starts and after this it will initialize the component in the initMockServer.js file then it will go to component.js file here manifest.json file will loaded from the metadata section and then it will exicute the init function of the componenet.js file So from here view will be rendered. 

Thanks and Regards,

Sachin Bidari.


文章来源: https://blogs.sap.com/2024/01/09/mock-server-configuration-in-sap-ui5-application./
如有侵权请联系:admin#unsafe.sh