I am new to loopback 4. I wish to write unit test cases for my project. However, I could't found proper example where they have used mocking service and using stubs.
Please assist me or share any example of properly written unit test(using mock service and stubs).
Thank You
Below is my code base:
Controller
export class CaptureController {
constructor(
@inject(RestBindings.Http.RESPONSE) private response: Response,
@service(HelperService) private helperService: HelperService,
) { }
@post('/capture', {
'x-controller-name': CaptureSwagger.controller,
summary: CaptureSwagger.summary,
description: CaptureSwagger.description,
responses: {
'200': CaptureSuccess.response,
'400': CommonHttpErrors(Messages.badRequest, 400, ''),
'401': CommonHttpErrors(
Messages.unauthorized,
401,
Messages.unauthorized,
),
},
})
async capture(
@requestBody() body: Capture,
): Promise<Response> {
const response = await this.helperService
.getGatewayService()
.capture(body);
const data = this.helperService.getGatewayKeys(
response,
TransactionType.COMPLETE,
);
const buildResponse = BuildResponse.prepare({data});
return this.response.json(buildResponse);
}
}
HelperService
@injectable({scope: BindingScope.TRANSIENT})
export class HelperService {
constructor(
@inject(RestBindings.Http.CONTEXT) private context: RequestContext,
@service(ConvergeService) private convergeService: ConvergeService,
) { }
getGatewayService() {
const merchantGateway: MerchantGateway =
this.context.getSync('merchantGateway');
const gatewayName: PaymentGateway | string = merchantGateway?.sysName
? merchantGateway.sysName
: '';
switch (gatewayName.toLowerCase()) {
case PaymentGateway.CONVERGE:
return this.convergeService;
default:
return this.nexioService;
}
}
}
ConvergeService
@injectable({scope: BindingScope.TRANSIENT})
export class ConvergeService {
/**
* Capture
* @param body Capture payment
*/
public capture = async (body: Capture) => {
const startAt = process.hrtime();
let errorResp = '';
const captureXml = `${this.xmlData}<ssl_transaction_type>cccomplete</ssl_transaction_type>
<ssl_amount>${body.data.amount}</ssl_amount>
<ssl_txn_id>${body.id}</ssl_txn_id>
</txn>`;
try {
const resp: {data: string} = await axiosApi.post(
`${this.convergeObj.apiUrl}`,
captureXml,
);
const jsonResp = this.parseXmlToJson(resp.data);
if (jsonResp?.txn?.errorCode) {
errorResp = resp.data;
throw new ResponseError.BadRequest(jsonResp.txn.errorMessage);
}
return jsonResp.txn ? jsonResp.txn : jsonResp;
} catch (err) {
this.commonService.getErrorResponse(err);
}
};
}
i will share a sample. You can customize it for your services, i think. We assume, we have a car service and simple price calculator function like this:
@injectable({scope: BindingScope.TRANSIENT})
export class CarService {
constructor(
@repository(CarRepository)
private carRepository: CarRepository,
) {}
async calculateCarPricesWithTaxes(tax: number): Promise<[]> {
const cars = await this.carRepository.find({where: {price: {gte: 10000}}});
return cars.map(car => (car.price * tax / 100) + car.price);
}
}
This service's unit test class like this:
describe('CarService', () => {
let carRepository: StubbedInstanceWithSinonAccessor<CarRepository>;
beforeEach(() => {
carRepository = createStubInstance(CarRepository);
carService = new CarService(carRepository);
});
after(() => {
sinon.restore();
});
describe('calculateCarPricesWithTaxes', () => {
it('should get new prices for cars', async () => {
const find = carRepository.stubs.find;
find.resolves([
{id: 1, price: 10000},
{id: 1, price: 20000},
]);
const res = await carService.calculateCarPricesWithTaxes(10);
expect(res).to.eql([11000, 22000]);
// expect(res).to.not.eql([110, 220]);
sinon.assert.calledWith(find, {where: {price: {gte: 10000}}});
// sinon.assert.calledOnce(find);
});
});
});
i hope this is helpful
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With