Skip to Content
Technical Articles

CAP: Unit Testing using Mocha and Chai

“A good developer will thoroughly unit test his code, while a lazy good developer will automate his unit tests”

Writing test scripts for unit testing automation is essential aspect for development team that follows Agile and DevOps methodology. Imagine an existing program needs to be enhanced with a new feature, a developer implements the new feature and unit test the changes, however, the developer didn’t unit test existing business scenarios, or didn’t test completely all scenarios because it’s just too many. Unknowingly, the latest changes introduced some bugs to existing features and it was detected only at the later stage of development lifecycle — and worst case, left undetected until the code reached the production system. And this case happens all the time.

So now if the program already have unit tests in place and there’s a process to execute it automatically, before deployment to a server environment, the developer is notified immediately of the error and is able to react right away and fix the problem.

In this blog, I will talk about setting up Mocha and Chai, a popular testing framework, in the context of SAP Cloud Application Programming Model.

 

 

Prerequisites


  • SAP Business Application Studio / Visual Studio Code
  • SAP Cloud Platform Account

 

Preparation


For this demo, I will be using the resulting project from my previous blog – Consume External Service – Part 2.

The working project can be found in this GitHub repository — Sample CAP Project.

If you have followed through the steps for testing the application in my previous blog, then you already know how to configure the package.json for testing with mock and real data.

So far, the way I’ve shown it is by nullifying the credentials property by adding double dash in front of it.

	"cds": {
		"requires": {
			"NorthWind": {
				"kind": "odata",
				"model": "srv/external/NorthWind",
				"--credentials": {
					"destination": "NorthWind"
				}
			}
		}
	}

By right, you don’t want to manually change your configuration just because you want to switch your testing method from mock to real data or vice versa. What you would prefer is to have a fixed configuration and it will depend on how you execute your application that it will use the appropriate configuration.

In order to achieve this, we need to update the configuration just like the one below:

	"cds": {
		"requires": {
			"NorthWind": {
				"kind": "odata",
				"model": "srv/external/NorthWind"
			}
		},
		"[local]": {
			"requires": {
				"NorthWind": {
					"kind": "odata",
					"model": "srv/external/NorthWind",
					"credentials": {
						"url": "https://services.odata.org/Experimental/OData/OData.svc"
					}
				}
			}
		},
		"[production]": {
			"requires": {
				"NorthWind": {
					"kind": "odata",
					"model": "srv/external/NorthWind",
					"credentials": {
						"destination": "NorthWind"
					}
				}
			}
		}
	}

This is to elaborate the use cases for each configuration:

  • 1. Testing using mock data
		"requires": {
			"NorthWind": {
				"kind": "odata",
				"model": "srv/external/NorthWind"
			}
		},

Run the application using command:

> cds watch
  • 2. Testing using real data direct from the external service
		"[local]": {
			"requires": {
				"NorthWind": {
					"kind": "odata",
					"model": "srv/external/NorthWind",
					"credentials": {
						"url": "https://services.odata.org/Experimental/OData/OData.svc"
					}
				}
			}
		},

Run the application using command:

> NODE_ENV=local cds watch
  • 3. This is the configuration that is meant to run in SCP Cloud Foundry
		"[production]": {
			"requires": {
				"NorthWind": {
					"kind": "odata",
					"model": "srv/external/NorthWind",
					"credentials": {
						"destination": "NorthWind"
					}
				}
			}
		}

For some reasons, the configuration above doesn’t work if you test locally using the command below. But if you deploy the application to SCP Cloud Foundry, the application will work without any issues.

Also, if you use this credentials without the [production] profile, the credentials.destination = NorthWind works locally. This is already taking into account that you have properly setup the credentials in the file default-env.json.

Update on 2 June 2020:

The issue of using [production] profile for local testing is really a bug in the framework — see below issue: https://github.com/sapmentors/cap-community/issues/67

Thanks to Klaus Kopecz for confirming that this issue exists!

> NODE_ENV=production cds watch

 

Setting up Mocha and Chai test frameworks


By now, we have properly configured our package.json to be able to call our mock data for automated unit testing. The next relevant thing to do is to start setting up Mocha and Chai frameworks.

  • 1. From the terminal, run the following command:
> npm install --save-dev mocha chai chai-http

This command will install the modules and update the package.json > devDependencies.

  • 2. Add a test npm script in the package.json that will be used for executing mocha test scripts.
	"scripts": {
		"test": "mocha tests/test.js --timeout 15000 --exit",
		"start": "npx cds run"
	},
  • 3. Now that we have an npm script to run for test execution, next step is to create the server of the OData service. Create a new folder called tests in the root folder. Then create a file called server.js inside this new folder. Finally, use the code below to bootstrap CDS and serve our application:
const cds = require("@sap/cds");

cds.exec("run", "--with-mocks", "--in-memory?");

module.exports = new Promise((resolve) => {
	cds.on('listening', () => {
		resolve(cds.app);
	});
});

As you can see from the bootstrap code, we are running cds programmatically rather than running it from a command line using cds watch. In fact, this is the code/function being called whenever we execute the cds watch command.

Note that running the application using mock data for unit testing ensures that our test cases will work correctly. When writing test scripts, you evaluate the data provided by the service with the expectation of what the value is supposed to be. Using mock data, then you can always be sure that the data returned by the application is consistent with the configured mock data.

  • 4. Create a new file called test.js inside the tests folder. This will host the test scripts.
const chai = require("chai");
const chaiHttp = require("chai-http");
const server = require("./server");

// Configure chai
chai.use(chaiHttp);
chai.should();

let app = null;

before((done) => {
	server.then((result) => {
		app = result;
		done();
	});
});

describe("Products Operation", () => {
	describe("GET /catalog/Products", () => {
		it("+ should return a list of products", (done) => {
			chai.request(app)
				.get("/catalog/Products")
				.end((error, response) => {
					try {
						response.should.have.status(200);
						response.body.value.should.be.an("array").to.have.lengthOf(2);
						done();
					} catch (error) {
						done(error);
					}
				});
		});
	});
});

That’s it! We are done with the setup!

 

Running the Tests


  • 1. From the terminal, run the command:
> npm run test

The result will look like this:

Note that we only have one test script in this case because the intention of this blog is to demonstrate on how to setup Mocha in the CAP Model context.

To know more about the Mocha test framework, I suggest that you browse through the official website for documentation and API reference — https://mochajs.org/.

  • 2. To demonstrate a failed test case scenario, let’s just add below test script before the first test at line #20:
		// This is just a demostration of a failed test case
		// The assertion was deliberately changed to trigger the test to fail
		it("- should return a list of products", (done) => {
			chai.request(app)
				.get("/catalog/Products")
				.end((error, response) => {
					try {
						response.should.have.status(200);
						response.body.value.should.be.an("array").to.have.lengthOf(12);
						done();
					} catch (error) {
						done(error);
					}
				});
		});

The result will look like this:

As you can see, the first test case failed, while the second test case is still passed.

 

Closing


Now you know how easy it is to setup Mocha framework for your automated unit testing. The work is mainly on writing efficient test scripts and making sure that you have properly mocked the data according to your test case scenario.

Writing test scripts and automating unit testing is essential for Agile development process where the development team can deliver the requirement fast but also with high quality.

In my next blog, I will continue on taking this project into a really automated process which is one of the stages of DevOps, the Continuous Integration and Continuous Deployment or CI/CD.

Update 8 June 2020:

CAP CI/CD using Azure DevOps – Part 1

 

~~~~~~~~~~~~~~~~

Appreciate it if you have any comments, suggestions, or questions. Cheers!~

2 Comments
You must be Logged on to comment or reply to a post.