UNPKG

azure-cli

Version:

Microsoft Azure Cross Platform Command Line tool

160 lines (139 loc) 7.78 kB
#### Where to put a test in the repository - **ASM** mode: - Test file should be put here - "/test/commands/" - Add a reference to the testfile in "/test/testlist.txt" - **ARM** mode: - Test file should be put here - "/test/commands/arm/{category-of-the-command}" - For example: All the tests related to the group category ```azure group -h" were put here "/test/commands/arm/group" - Add a reference to the testfile in "/test/testlist**arm**.txt" #### Structure of a test A sample test to explain the test structure. Please pay close attention to the comments in the following test snippet. ```javascript 'use strict'; //"should.js" (http://unitjs.com/guide/should-js.html) is used for asserting the outcomes. var should = require('should'); //"/test/framework/arm-cli-test.js" is the suite used for writing tests in "ARM" mode. //"/test/framework/cli-test.js" is the suite used for writing tests in "ASM" mode. var CLITest = require('../../../framework/arm-cli-test'); //Always provide a testPrefix. This would be the name of the directory //in which the test recordings would be stored for playback purposes //for example: "/test/recordings/arm-cli-location-tests/*" var testprefix = 'arm-cli-location-tests'; var sitename; var createdSites = []; //List of requiredEnvironment variables for this test. If the envt. variable is not set //and a default value is provided then it will be used in the test, else the test will //throw an error letting the user know the list of required envt variables that need to be set. var requiredEnvironment = [ { name: 'AZURE_SITE_TEST_LOCATION', defaultValue: 'East US'}, 'AZURE_STORAGE_ACCESS_KEY' ]; //We are using a poplular javascript testing framework named "mocha" (http://mochajs.org/) for writing tests. //As per mocha, describe() defines a "test-suite" and it() defines a "test" in a test-suite. describe('arm', function () { describe('location', function () { var suite; //before is executed once at the start of the this test-suite. before(function (done) { suite = new CLITest(this, testprefix, requiredEnvironment); //setupSuite is a hook provided for the developer to perform steps that //need to be performed once before the first test gets executed. //A. If nothing needs to be performed then setupSuite() needs to be called as follows: suite.setupSuite(done); //B. Let us assume that a new site needs to be created once, that will be used by every test. //Then we shall do something like this: suite.setupSuite(function () { //During RECORD mode, generateId will write the random test id to the recording file. //This id will be read from the file during PLAYBACK mode sitename = suite.generateId( "test-site" /*some good site prefix for you to identify the sites created by your test*/, createdSites /*An array to maintain the list of created sites. This is useful to delete the list of created sites in teardown*/ ); suite.execute("site create --location %s %s --json" /*Azure command to execute*/, process.env.AZURE_SITE_TEST_LOCATION, sitename, function (result) { //test to verify the successful execution of the command result.exitStatus.should.equal(0); //done is an important callback that signals mocha that the current phase in the //test is complete and the mocha runner should move to the next phase in the test done(); }); }); }); //after is execute once at the end of this test-suite after(function (done) { //teardownSuite is a hook provided for the developer to perform steps that //need to be performed once after the execution of the entire test-suite is complete. //A. If nothing needs to be performed then setupSuite() needs to be called as follows: suite.teardownSuite(done); //B. The created artifacts in setupSuite() need to be deleted, so that the suite leaves the //environment in a consistent state. //Then we shall do something like this: suite.teardownSuite(function () { //delete all the artifacts that were created during setup createdSites.forEach(function (item) { suite.execute('site delete %s -q --json', item, function (result) { result.exitStatus.should.equal(0); }); }); done(); }); }); //beforeEach is executed everytime before the test starts beforeEach(function (done) { //setupTest is a hook provided for the developer to perform steps that //need to be performed before every test //Mechanism to add custom steps for setupTest() is the same that is explained above in setupSuite() suite.setupTest(done); }); //afterEach is executed everytime after the test execution is complete, //irrespective of success or failure afterEach(function (done) { //teardownTest is a hook provided for the developer to perform steps that //need to performed after every test //Mechanism to add custom steps for teardownTest() is the same that is explained above in teardownSuite() suite.teardownTest(done); }); describe('list', function () { //positive test it('should work', function (done /*Always provide the done callback as a parameter*/) { //execute the command //It is very important to use the --json switch as it becomes easy to parse the output. suite.execute('location list --json', function (result) { //check for zero exit code if you are expecting a success or 1 if you are expecting a failure result.exitStatus.should.equal(0); //parse the expected output from the text property of the result var allResources = JSON.parse(result.text); allResources.some(function (res) { return res.name.match(/Microsoft.Sql\/servers/gi); }).should.be.true; //do not forget the done() callback. done(); }); }); //negative test it('should fail when an invalid resource group is provided', function (done /*Always provide the done callback as a parameter*/) { suite.execute('group log show -n %s --json', 'random_group_name', function (result) { result.exitStatus.should.equal(1); //errorText property of result will contain the expected error message. Doing a Regex match //is always the best option, as one need not change the test if there is a minor modification //in the error message from the server side. result.errorText.should.match(/.*Resource group \'random_group_name\' could not be found.*/ig); //do not forget the done() callback. done(); }); }); }); }); }); ``` #### Test Recording Structure Steps to set the **RECORD** mode and selective test recording can be found [here](./TestModes.md). - **Suite** - There is a **"suite-*"** recording file for the test file. - Ids of the artifacts generated during setupSuite() are recorded in this file and retrieved during playback - Test Recording is **not done** during setupSuite() and teardownSuite(). Random ids generated for the created artifacts during this phase, are stored in the suite recording file and are retrieved during playback. - **Test** - Every test is recorded in a separate file. This makes it easier to re-record selective tests due to failures or server side changes. - **Note** If the test is using an artifact, created during **setupSuite()** then all the tests in that suite will have to be re-recorded