Search code examples
javascriptazureunit-testing

Understanding unit test azure functions (mock or stub)?



I have been trying to learn Unit Test for quite some time, but I keep having some difficulties with some topics.
const { BlobServiceClient } = require('@azure/storage-blob');
const Mqtt = require('azure-iot-device-mqtt').Mqtt;
const DeviceClient = require('azure-iot-device').Client;

_connectToCloud(){
   this.blobServiceClient = BlobServiceClient.fromConnectionString(this.Blobcredentials);
   this.azureColdContainer = this.blobServiceClient.getContainerClient(`name1`);
   this.azureWarmContainer = this.blobServiceClient.getContainerClient(`name1`);
   this.iotHubMQTTclient = DeviceClient.fromConnectionString(this.IOTcredentials, Mqtt);
}

I have a function in my class (_connectToCloud) that as the name suggests connects to azure cloud (blob storage, iothub).
Now I want to code coverage these lines of code, but I'm stuck and don't know how best to proceed. Could someone please explaine to me if i need to stub or to mock the object?


Solution

  • Stubbing implements the behaviour of the particular method or service on how it will respond or behave in a particular solution. You can test its behaviour and expect dummy response in return when you're stubbing a particular service. In stubbing you may test different situations and manage how the stubbed objects behave without really connecting to the Azure services. You can create a stub objects around, BlobServiceClient.fromConnectionString and DeviceClient.fromConnectionString and stimulate their response.

    Here's an example of stubbing :-

    const { BlobServiceClient } = require('@azure/storage-blob');
    const Mqtt = require('azure-iot-device-mqtt').Mqtt;
    const DeviceClient = require('azure-iot-device').Client;
    
    describe('YourClass', () => {
      let blobServiceClientMock;
      let blobContainerClientMock;
      let deviceClientMock;
    
      beforeEach(() => {
        blobContainerClientMock = {
          // Mock any methods you need to use from blobContainerClient
          // For example:
          doSomething: jest.fn()
        };
    
        blobServiceClientMock = {
          getContainerClient: jest.fn().mockReturnValue(blobContainerClientMock)
        };
    
        deviceClientMock = {
          // Mock any methods you need to use from deviceClient
          // For example:
          sendEvent: jest.fn()
        };
    
        BlobServiceClient.fromConnectionString = jest.fn().mockReturnValue(blobServiceClientMock);
        DeviceClient.fromConnectionString = jest.fn().mockReturnValue(deviceClientMock);
      });
    
      afterEach(() => {
        jest.restoreAllMocks();
      });
    
      it('_connectToCloud should connect to Azure cloud', () => {
        // Create an instance of your class and call _connectToCloud
        const yourInstance = new YourClass();
        yourInstance._connectToCloud();
    
        // Assert that the expected calls were made
        expect(BlobServiceClient.fromConnectionString).toHaveBeenCalledTimes(1);
        expect(BlobServiceClient.fromConnectionString).toHaveBeenCalledWith(yourInstance.Blobcredentials);
    
        expect(blobServiceClientMock.getContainerClient).toHaveBeenCalledTimes(2);
        expect(blobServiceClientMock.getContainerClient).toHaveBeenCalledWith('name1');
    
        expect(DeviceClient.fromConnectionString).toHaveBeenCalledTimes(1);
        expect(DeviceClient.fromConnectionString).toHaveBeenCalledWith(yourInstance.IOTcredentials, Mqtt);
    
        // Assert any other expectations you have on the mocked methods
        // For example:
        expect(blobContainerClientMock.doSomething).toHaveBeenCalledTimes(1);
        expect(deviceClientMock.sendEvent).toHaveBeenCalledTimes(1);
      });
    });
    

    You can use Jest module in JS to test the Functions.

    Mocking adds an extra layer in your testing and it tests the interactions on dependencies and how the entire code interacts and responds. Mocking helps you to test exact behaviour of your Azure service clients by mimicing them. It is possible to create mock objects, specify expectations, and validate interactions using mocking tools like sinon.js or jest for verification of the interactions.

    As you're using (_connectToCloud) class, Which uses Blob service connection string to connect to azure you can make use of Mocking method in your code to actually simulate the response of your function with azure service client. You can also use the combination of Mock and stub:- You can stub BlobServiceClient.fromConnectionString and DeviceClient.fromConnectionString and Mock the response in getContainerClient

    I created one Mocking test for your code like below:-

    Mocking code:-

    const { BlobServiceClient } = require('@azure/storage-blob');
    const Mqtt = require('azure-iot-device-mqtt').Mqtt;
    const DeviceClient = require('azure-iot-device').Client;
    
    class YourClass {
      constructor(Blobcredentials, IOTcredentials) {
        this.Blobcredentials = Blobcredentials;
        this.IOTcredentials = IOTcredentials;
        this.blobServiceClient = null;
        this.azureColdContainer = null;
        this.azureWarmContainer = null;
        this.iotHubMQTTclient = null;
      }
    
      _connectToCloud() {
        this.blobServiceClient = BlobServiceClient.fromConnectionString(this.Blobcredentials);
        this.azureColdContainer = this.blobServiceClient.getContainerClient('name1');
        this.azureWarmContainer = this.blobServiceClient.getContainerClient('name1');
        this.iotHubMQTTclient = DeviceClient.fromConnectionString(this.IOTcredentials, Mqtt);
      }
    }
    
    // Mocking example using Jest
    describe('YourClass', () => {
      let yourClassInstance;
    
      beforeEach(() => {
        yourClassInstance = new YourClass('fake-blob-credentials', 'fake-iot-credentials');
      });
    
      test('_connectToCloud', () => {
        const mockBlobServiceClient = {
          getContainerClient: jest.fn().mockReturnThis()
        };
        BlobServiceClient.fromConnectionString = jest.fn().mockReturnValue(mockBlobServiceClient);
        DeviceClient.fromConnectionString = jest.fn();
    
        yourClassInstance._connectToCloud();
    
        expect(BlobServiceClient.fromConnectionString).toHaveBeenCalledWith('fake-blob-credentials');
        expect(mockBlobServiceClient.getContainerClient).toHaveBeenCalledTimes(2);
        expect(mockBlobServiceClient.getContainerClient).toHaveBeenCalledWith('name1');
        expect(DeviceClient.fromConnectionString).toHaveBeenCalledWith('fake-iot-credentials', Mqtt);
      });
    });
    

    Output:-

    Command:-

    npx jest --verbose
    

    enter image description here