Как смоделировать метод класса, который инициализируется внутри другого класса в typescript с использованием ts mockito?

#typescript #unit-testing #jsmockito

#typescript #модульное тестирование #jsmockito

Вопрос:

Это мой класс, который я хочу протестировать с использованием тестовой платформы mocha-chai в typescript. Я использую ts-mockito для издевательства.

 export class ClassA implements IClassA {

    private classAResource: IClassAResource;

    constructor(){
         this.classAResource= new ClassAResource();
    }

    public async cancel(jobid){
       const job = this.classAResource.getJob(jobid);
       //cancel logic
    }
}
  

ClassAResource класс выглядит следующим образом,

 export class StreamResource implements IStreamResource {

private jobs: Map<string, Job>;

 constructor(){
 this.jobs= new Map();
 }

public async createJob(): Promise<Job> {
//add the job to map
}

public async getJob(jobid): Promise<Job>{
//return the specified job item from map
}


}
  

В моем тесте я пытаюсь смоделировать метод getJob ClassAResource следующим образом,

 const classAResource: IClassAResource = new ClassAResource ();
 const classAResourceSpy = spy(classAResource);

 when(classAResourceSpy.getJob(anyString())).thenResolve(job); 
  

И я вызываю метод ClassA cancel следующим образом,

 classA.cancel(jobid)
  

Я ожидаю, что вызов getJob в методе cancel будет смоделирован и вернет объект job.

Но тест работает не в соответствии с моими ожиданиями. Макет не отображается, и getJob () переходит к фактической реализации и возвращает undefined.

Я читал онлайн, эта проблема связана с инициализациями конструктора в классе ClassAResource.

Я удалил конструктор и попробовал, и теперь макет getJob работает.

Но мне нужен конструктор для создания экземпляра объекта map и возможность поддерживать задания.

Есть ли какой-нибудь обходной путь, с помощью которого я могу смоделировать getJob() с помощью конструктора на месте?

Я делаю что-то не так здесь?

Я относительно новичок в typescript и ts-mockito, и любая помощь очень ценится.

Комментарии:

1. Можете ли вы указать свой точный тестовый код?

Ответ №1:

На самом деле это не имеет ничего общего конкретно с TypeScript, а скорее проблема с проверяемостью из-за нарушения принципа инверсии зависимостей.
Создание экземпляров членов в конструкторе класса вызывает проблему с проверяемостью, поскольку контроль над созданием экземпляра находится в руках тестируемого кода (он же «тестируемый модуль», «тестируемый класс» и т.д.). Это означает, что у вас практически нет контроля над тем, какой экземпляр будет иметь тестируемый класс.

Существуют некоторые библиотеки-макеты, которые допускают «враждебный захват» экземпляра определенных классов (по крайней мере, для Java, см. PowerMock), но их следует использовать очень экономно, если вообще следует, поскольку они способствуют сохранению отсутствия возможности тестирования.

Вместо создания экземпляра IClassAResource из конструктора ClassA , вы должны либо получить экземпляр с помощью инъекции (DI, constructor, setter method и т.д.), Либо, по крайней мере, использовать factory / builder. Таким образом, ваш класс станет тестируемым, и ваш дизайн будет улучшен.

В целом, вы должны придерживаться всех принципов SOLID, поскольку они, по крайней мере на данный момент, считаются наиболее точным и кратким набором хороших принципов проектирования ООП.