improve tests

This commit is contained in:
sbriat 2023-09-19 10:54:23 +02:00
parent 075a856d09
commit efea6fe13c
6 changed files with 383 additions and 4 deletions

View File

@ -29,7 +29,7 @@ export class RouteCompleter extends Completer {
break; break;
case RouteCompleterType.DETAILED: case RouteCompleterType.DETAILED:
const detailedCandidateRoute = const detailedCandidateRoute =
await this.query.routeProvider.getBasic( await this.query.routeProvider.getDetailed(
(candidate.getProps().carpoolSteps as WayStep[]).map( (candidate.getProps().carpoolSteps as WayStep[]).map(
(wayStep: WayStep) => wayStep.point, (wayStep: WayStep) => wayStep.point,
), ),

View File

@ -1,7 +1,10 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { RouteProviderPort } from '../core/application/ports/route-provider.port'; import { RouteProviderPort } from '../core/application/ports/route-provider.port';
import { GetRouteControllerPort } from '@modules/geography/core/application/ports/get-route-controller.port'; import { GetRouteControllerPort } from '@modules/geography/core/application/ports/get-route-controller.port';
import { AD_GET_BASIC_ROUTE_CONTROLLER } from '../ad.di-tokens'; import {
AD_GET_BASIC_ROUTE_CONTROLLER,
AD_GET_DETAILED_ROUTE_CONTROLLER,
} from '../ad.di-tokens';
import { Point, Route } from '@modules/geography/core/domain/route.types'; import { Point, Route } from '@modules/geography/core/domain/route.types';
@Injectable() @Injectable()
@ -9,6 +12,8 @@ export class RouteProvider implements RouteProviderPort {
constructor( constructor(
@Inject(AD_GET_BASIC_ROUTE_CONTROLLER) @Inject(AD_GET_BASIC_ROUTE_CONTROLLER)
private readonly getBasicRouteController: GetRouteControllerPort, private readonly getBasicRouteController: GetRouteControllerPort,
@Inject(AD_GET_DETAILED_ROUTE_CONTROLLER)
private readonly getDetailedRouteController: GetRouteControllerPort,
) {} ) {}
getBasic = async (waypoints: Point[]): Promise<Route> => getBasic = async (waypoints: Point[]): Promise<Route> =>
@ -17,7 +22,7 @@ export class RouteProvider implements RouteProviderPort {
}); });
getDetailed = async (waypoints: Point[]): Promise<Route> => getDetailed = async (waypoints: Point[]): Promise<Route> =>
await this.getBasicRouteController.get({ await this.getDetailedRouteController.get({
waypoints, waypoints,
}); });
} }

View File

@ -0,0 +1,117 @@
import { AdRepositoryPort } from '@modules/ad/core/application/ports/ad.repository.port';
import { RouteProviderPort } from '@modules/ad/core/application/ports/route-provider.port';
import {
Algorithm,
Selector,
} from '@modules/ad/core/application/queries/match/algorithm.abstract';
import { MatchQuery } from '@modules/ad/core/application/queries/match/match.query';
import { Waypoint } from '@modules/ad/core/application/types/waypoint.type';
import { Frequency, Role } from '@modules/ad/core/domain/ad.types';
import { CandidateEntity } from '@modules/ad/core/domain/candidate.entity';
import { MatchEntity } from '@modules/ad/core/domain/match.entity';
const originWaypoint: Waypoint = {
position: 0,
lat: 48.689445,
lon: 6.17651,
houseNumber: '5',
street: 'Avenue Foch',
locality: 'Nancy',
postalCode: '54000',
country: 'France',
};
const destinationWaypoint: Waypoint = {
position: 1,
lat: 48.8566,
lon: 2.3522,
locality: 'Paris',
postalCode: '75000',
country: 'France',
};
const mockRouteProvider: RouteProviderPort = {
getBasic: jest.fn(),
getDetailed: jest.fn(),
};
const matchQuery = new MatchQuery(
{
frequency: Frequency.PUNCTUAL,
fromDate: '2023-08-28',
toDate: '2023-08-28',
schedule: [
{
time: '01:05',
},
],
waypoints: [originWaypoint, destinationWaypoint],
},
mockRouteProvider,
);
const mockAdRepository: AdRepositoryPort = {
insertExtra: jest.fn(),
findOneById: jest.fn(),
findOne: jest.fn(),
insert: jest.fn(),
update: jest.fn(),
updateWhere: jest.fn(),
delete: jest.fn(),
count: jest.fn(),
healthCheck: jest.fn(),
getCandidateAds: jest.fn(),
};
class SomeSelector extends Selector {
select = async (): Promise<CandidateEntity[]> => [
CandidateEntity.create({
id: 'cc260669-1c6d-441f-80a5-19cd59afb777',
role: Role.DRIVER,
driverWaypoints: [
{
lat: 48.678454,
lon: 6.189745,
},
{
lat: 48.84877,
lon: 2.398457,
},
],
passengerWaypoints: [
{
lat: 48.849445,
lon: 6.68651,
},
{
lat: 47.18746,
lon: 2.89742,
},
],
driverDistance: 350145,
driverDuration: 13548,
spacetimeDetourRatio: {
maxDistanceDetourRatio: 0.3,
maxDurationDetourRatio: 0.3,
},
}),
];
}
class SomeAlgorithm extends Algorithm {
constructor(
protected readonly query: MatchQuery,
protected readonly repository: AdRepositoryPort,
) {
super(query, repository);
this.selector = new SomeSelector(query, repository);
this.processors = [];
}
}
describe('Abstract Algorithm', () => {
it('should return matches', async () => {
const someAlgorithm = new SomeAlgorithm(matchQuery, mockAdRepository);
const matches: MatchEntity[] = await someAlgorithm.match();
expect(matches).toHaveLength(1);
});
});

View File

@ -0,0 +1,154 @@
import {
RouteCompleter,
RouteCompleterType,
} from '@modules/ad/core/application/queries/match/completer/route.completer';
import { MatchQuery } from '@modules/ad/core/application/queries/match/match.query';
import { AlgorithmType } from '@modules/ad/core/application/types/algorithm.types';
import { Waypoint } from '@modules/ad/core/application/types/waypoint.type';
import { Frequency, Role } from '@modules/ad/core/domain/ad.types';
import { CandidateEntity } from '@modules/ad/core/domain/candidate.entity';
import { Target } from '@modules/ad/core/domain/candidate.types';
import { Actor } from '@modules/ad/core/domain/value-objects/actor.value-object';
import { Point } from '@modules/ad/core/domain/value-objects/point.value-object';
const originWaypoint: Waypoint = {
position: 0,
lat: 48.689445,
lon: 6.17651,
houseNumber: '5',
street: 'Avenue Foch',
locality: 'Nancy',
postalCode: '54000',
country: 'France',
};
const destinationWaypoint: Waypoint = {
position: 1,
lat: 48.8566,
lon: 2.3522,
locality: 'Paris',
postalCode: '75000',
country: 'France',
};
const matchQuery = new MatchQuery(
{
algorithmType: AlgorithmType.PASSENGER_ORIENTED,
driver: true,
passenger: true,
frequency: Frequency.PUNCTUAL,
fromDate: '2023-08-28',
toDate: '2023-08-28',
schedule: [
{
time: '07:05',
},
],
strict: false,
waypoints: [originWaypoint, destinationWaypoint],
},
{
getBasic: jest.fn().mockImplementation(() => ({
distance: 350101,
duration: 14422,
fwdAzimuth: 273,
backAzimuth: 93,
distanceAzimuth: 336544,
points: [],
})),
getDetailed: jest.fn().mockImplementation(() => ({
distance: 350102,
duration: 14423,
fwdAzimuth: 273,
backAzimuth: 93,
distanceAzimuth: 336544,
points: [],
})),
},
);
const candidate: CandidateEntity = CandidateEntity.create({
id: 'cc260669-1c6d-441f-80a5-19cd59afb777',
role: Role.DRIVER,
driverWaypoints: [
{
lat: 48.678454,
lon: 6.189745,
},
{
lat: 48.84877,
lon: 2.398457,
},
],
passengerWaypoints: [
{
lat: 48.689445,
lon: 6.17651,
},
{
lat: 48.8566,
lon: 2.3522,
},
],
driverDistance: 350145,
driverDuration: 13548,
spacetimeDetourRatio: {
maxDistanceDetourRatio: 0.3,
maxDurationDetourRatio: 0.3,
},
}).setCarpoolPath([
{
point: new Point({
lat: 48.689445,
lon: 6.17651,
}),
actors: [
new Actor({
role: Role.DRIVER,
target: Target.START,
}),
new Actor({
role: Role.PASSENGER,
target: Target.START,
}),
],
},
{
point: new Point({
lat: 48.8566,
lon: 2.3522,
}),
actors: [
new Actor({
role: Role.DRIVER,
target: Target.FINISH,
}),
new Actor({
role: Role.PASSENGER,
target: Target.FINISH,
}),
],
},
]);
describe('Route completer', () => {
it('should complete candidates with basic setting', async () => {
const routeCompleter: RouteCompleter = new RouteCompleter(
matchQuery,
RouteCompleterType.BASIC,
);
const completedCandidates: CandidateEntity[] =
await routeCompleter.complete([candidate]);
expect(completedCandidates.length).toBe(1);
expect(completedCandidates[0].getProps().distance).toBe(350101);
});
it('should complete candidates with detailed setting', async () => {
const routeCompleter: RouteCompleter = new RouteCompleter(
matchQuery,
RouteCompleterType.DETAILED,
);
const completedCandidates: CandidateEntity[] =
await routeCompleter.complete([candidate]);
expect(completedCandidates.length).toBe(1);
expect(completedCandidates[0].getProps().distance).toBe(350102);
});
});

View File

@ -1,4 +1,7 @@
import { AD_GET_BASIC_ROUTE_CONTROLLER } from '@modules/ad/ad.di-tokens'; import {
AD_GET_BASIC_ROUTE_CONTROLLER,
AD_GET_DETAILED_ROUTE_CONTROLLER,
} from '@modules/ad/ad.di-tokens';
import { Point } from '@modules/ad/core/application/types/point.type'; import { Point } from '@modules/ad/core/application/types/point.type';
import { RouteProvider } from '@modules/ad/infrastructure/route-provider'; import { RouteProvider } from '@modules/ad/infrastructure/route-provider';
import { GetRouteControllerPort } from '@modules/geography/core/application/ports/get-route-controller.port'; import { GetRouteControllerPort } from '@modules/geography/core/application/ports/get-route-controller.port';
@ -38,6 +41,30 @@ const mockGetBasicRouteController: GetRouteControllerPort = {
})), })),
}; };
const mockGetDetailedRouteController: GetRouteControllerPort = {
get: jest.fn().mockImplementationOnce(() => ({
distance: 350102,
duration: 14423,
fwdAzimuth: 273,
backAzimuth: 93,
distanceAzimuth: 336544,
points: [
{
lon: 6.1765102,
lat: 48.689445,
},
{
lon: 4.984578,
lat: 48.725687,
},
{
lon: 2.3522,
lat: 48.8566,
},
],
})),
};
describe('Route provider', () => { describe('Route provider', () => {
let routeProvider: RouteProvider; let routeProvider: RouteProvider;
@ -49,6 +76,10 @@ describe('Route provider', () => {
provide: AD_GET_BASIC_ROUTE_CONTROLLER, provide: AD_GET_BASIC_ROUTE_CONTROLLER,
useValue: mockGetBasicRouteController, useValue: mockGetBasicRouteController,
}, },
{
provide: AD_GET_DETAILED_ROUTE_CONTROLLER,
useValue: mockGetDetailedRouteController,
},
], ],
}).compile(); }).compile();
@ -67,4 +98,13 @@ describe('Route provider', () => {
expect(route.distance).toBe(350101); expect(route.distance).toBe(350101);
expect(route.duration).toBe(14422); expect(route.duration).toBe(14422);
}); });
it('should provide a detailed route', async () => {
const route: Route = await routeProvider.getDetailed([
originPoint,
destinationPoint,
]);
expect(route.distance).toBe(350102);
expect(route.duration).toBe(14423);
});
}); });

View File

@ -0,0 +1,63 @@
import { GetDetailedRouteController } from '@modules/geography/interface/controllers/get-detailed-route.controller';
import { RouteMapper } from '@modules/geography/route.mapper';
import { QueryBus } from '@nestjs/cqrs';
import { Test, TestingModule } from '@nestjs/testing';
const mockQueryBus = {
execute: jest.fn(),
};
const mockRouteMapper = {
toPersistence: jest.fn(),
toDomain: jest.fn(),
toResponse: jest.fn(),
};
describe('Get Detailed Route Controller', () => {
let getDetailedRouteController: GetDetailedRouteController;
beforeAll(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
{
provide: QueryBus,
useValue: mockQueryBus,
},
{
provide: RouteMapper,
useValue: mockRouteMapper,
},
GetDetailedRouteController,
],
}).compile();
getDetailedRouteController = module.get<GetDetailedRouteController>(
GetDetailedRouteController,
);
});
afterEach(async () => {
jest.clearAllMocks();
});
it('should be defined', () => {
expect(getDetailedRouteController).toBeDefined();
});
it('should get a route', async () => {
jest.spyOn(mockQueryBus, 'execute');
await getDetailedRouteController.get({
waypoints: [
{
lat: 48.689445,
lon: 6.17651,
},
{
lat: 48.8566,
lon: 2.3522,
},
],
});
expect(mockQueryBus.execute).toHaveBeenCalledTimes(1);
});
});