tamara d
tamara d

Reputation: 330

Create Object with Sinon stub as input to constructor

I'm writing unit tests with mocha, chai and sinon in TypeScript. I need to test a class thats constructor expects an object as input parameter, that I want to mock because it is too complex to create. Also some methods of the class use properties of that specific input paramter object. So I also would need to mock methods of that mocked object.

Maybe some code makes it clearer:

My class looks like this (simplified):

class Controller {
   constructor(context: Context) {
        this._context = context;
   }
   protected get elasticSearch(): Client {
         return this._context.clients.elasticSearch;
   }

   // the next method should be tested
   public async getSomething(input1: string, input2: string): Promise<ResultObject> {
       const result = new ResultObject();
       await this.elasticSearch.search(query).then((_res)=>{
           // do something with _res
           result.prop = _res;
       });
       return result;
   }
}

Now I would like to test the getSomething function. For that I first need to create a Controller object. But the constructor needs a Context object, that I do not have. For that I already tried both of the following:

const controllerStub = sinon.createStubInstance(Controller);
controllerStub.elasticSearch = sinon.stub();
--------------------------------------------------
const contextMock = <Context>{};
const controller = new Controller(contextMock);
controller.elasticSearch = sinon.stub();
controller.elasticSearch.search = sinon.stub();

which both didn't work because property elasticSearch doesn't exist on type SinonStubbedInstance<Controller> and I cannot set the elasticSearch property in the first place as it has only a getter.

So now I really don't know what to mock and how to test that getSomething function. In the best case I want to say that the elasticsearch.search(query) returns a defined value and this specific value should be handled further in the .then part. I want to skip the elasticSearch access but still want the .then part to be run.

All the documentation about stubs and nested stubs didn't help me.

Upvotes: 0

Views: 554

Answers (1)

tamara d
tamara d

Reputation: 330

So I managed a working solution. It's probably not best practice but it's the best I could do:

For the Context object I just create an empty Object like that:

contextMock = <Context><unknown>{
                  clients: {
                      elasticSearch: new Client()
                  }
               }

then I create with that the controller object:

controller = new Controller(contextMock);

then I can mock the functions of the elasticSearch property like that:

searchStub = sinon.stub(contextMock.clients.elasticSearch, 'search');

And then I have all the things I need to test the class.

Upvotes: 1

Related Questions