私の残りのアーキテクチャには、コントローラー(http要求を処理する)とサービス(データを提供するビジネスロジック)があります。
コントローラーをテストするために、固定応答を提供するためにサービスをスタブ化しようとしていますが、カスタムオブジェクトを引数として必要とするメソッドをスタブ化する方法がわかりませんでした(引数がリテラルの場合、それは機能します)。
カスタムオブジェクト(ファーム)では、サービスメソッドからPromiseを受け取らないため、スタブが機能しません。これはエラーです。
TypeError:FarmsController.createFarm(/Users/giovannimarino/Projects/rt-cloud/services/farms/src/farms/farms.controller.ts:17:17)でnullのプロパティ 'then'を読み取れません
farms.controller.spec.ts
describe('FarmsController', () => {
const farmsServiceMock: FarmsService = mock(FarmsService);
let controller: FarmsController;
interface TestData {
farm: Farm;
}
let testData: TestData;
beforeEach(() => {
reset(farmsServiceMock);
const farmsServiceMockInstance: FarmsService = instance(farmsServiceMock);
controller = new FarmsController(farmsServiceMockInstance);
testData = {
farm: <Farm> {
name: 'CattD',
imageUrl: 'img/farm-123b341.png',
lang: 'en',
}
};
});
describe('createFarm function', () => {
describe('success', () => {
it('should return HTTP 200 OK', async () => {
when(farmsServiceMock.createFarm(testData.farm)).thenReturn(Promise.resolve<Farm>(testData.farm));
const pathParameters: PathParameter = {
name: 'CattD',
};
const bodyRequest: Body = {
name: testData.farm.name,
imageUrl: testData.farm.imageUrl,
lang: testData.farm.lang
};
const response: ApiResponseParsed<Farm> = await callSuccess<Farm>(controller.createFarm, pathParameters, bodyRequest);
expect(response.statusCode).to.equal(HttpStatusCode.Ok);
});
});
});
});
farm.controller.ts
export class FarmsController {
public constructor(private readonly _service: FarmsService) {
}
public createFarm: ApiHandler = (event: ApiEvent, context: ApiContext, callback: ApiCallback): void => {
if (!event.body) {
throw new Error('Empty input');
}
const input: Farm = <Farm> JSON.parse(event.body);
this._service.createFarm(input)
.then((data: Farm) => {
return ResponseBuilder.created(data, callback); // tslint:disable-line arrow-return-shorthand
})
.catch((error: ErrorResult) => {
if (error instanceof NotFoundResult) {
return ResponseBuilder.notFound(error.code, error.description, callback);
}
if (error instanceof ForbiddenResult) {
return ResponseBuilder.forbidden(error.code, error.description, callback);
}
return ResponseBuilder.internalServerError(error, callback);
});
}
}
farm.service.ts
export class FarmsService {
public constructor(private readonly _repo: FarmsRepository) {
}
public async createFarm(farm: Farm): Promise<Farm> {
try {
return this._repo.create(farm);
} catch (error) {
throw error;
}
}
}
callSuccess
export const callSuccess: SuccessCaller = <T>(handler: ApiHandler,
pathParameters?: PathParameter, body?: Body): Promise<ApiResponseParsed<T>> => {
// tslint:disable-next-line typedef (Well-known constructor.)
return new Promise((resolve, reject) => {
const event: ApiEvent = <ApiEvent> {};
if (pathParameters) {
event.pathParameters = pathParameters;
}
if (body) {
event.body = JSON.stringify(body);
}
handler(event, <ApiContext> {}, (error?: Error | null | string, result?: ApiResponse): void => {
if (typeof result === 'undefined') {
reject('No result was returned by the handler!');
return;
}
const parsedResult: ApiResponseParsed<T> = result as ApiResponseParsed<T>;
parsedResult.parsedBody = JSON.parse(result.body) as T;
resolve(parsedResult);
});
});
};
同じ問題に直面し、カスタムオブジェクトをパラメーターとして渡すdeepEqual()関数を使用して解決しました。
import {deepEqual, instance, mock, when} from 'ts-mockito';
...
const myCustomObj = {
userId: 123
};
when(mockedObj.myMethod(deepEqual(myCustomObj))).thenResolve(myPromise);
...