Як заглушити метод макетного об'єкту жасмину?


76

Згідно з документацією про жасмин, макет можна створити так:

jasmine.createSpyObj(someObject, ['method1', 'method2', ... ]);

Як заглушити один із цих методів? Наприклад, якщо ви хочете перевірити, що відбувається, коли метод видає виняток, як би ви це зробили?


3
Ви можете спробувати зв’язати це ланцюжком andCallThrough. Це чітко не задокументовано: /
EricG

Відповіді:


117

Вам потрібно ланцюг method1, method2як прокоментував EricG, але не з andCallThrough()(або and.callThrough()у версії 2.0). Він делегуватиме реальну реалізацію .

У цьому випадку вам потрібно зв’язати and.callFake()та передати функцію, яку ви хочете викликати (може викинути виняток або що завгодно):

var someObject = jasmine.createSpyObj('someObject', [ 'method1', 'method2' ]);
someObject.method1.and.callFake(function() {
    throw 'an-exception';
});

І тоді ви можете перевірити:

expect(yourFncCallingMethod1).toThrow('an-exception');

7
Жасмин 2.0 змінив синтаксис .and.callFake(), .and.callThrough(), .and.returnValue() jasmine.github.io/2.0/introduction.html#section-Spies
alxndr

20

Якщо ви використовуєте Typescript, корисно передати метод як Jasmine.Spy. У наведеній вище відповіді (як не дивно, у мене немає представника для коментарів):

(someObject.method1 as Jasmine.Spy).and.callFake(function() {
  throw 'an-exception';
});

Я не знаю, чи я надмірно інженерний, бо мені не вистачає знань ...

Для машинопису я хочу:

  • Інтеллісенс від основного типу
  • Можливість знущатися над методами, що використовуються у функції

Я знайшов це корисним:

namespace Services {
    class LogService {
        info(message: string, ...optionalParams: any[]) {
            if (optionalParams && optionalParams.length > 0) {
                console.log(message, optionalParams);
                return;
            }

            console.log(message);
        }
    }
}

class ExampleSystemUnderTest {
    constructor(private log: Services.LogService) {
    }

    doIt() {
        this.log.info('done');
    }
}

// I export this in a common test file 
// with other utils that all tests import
const asSpy = f => <jasmine.Spy>f;

describe('SomeTest', () => {
    let log: Services.LogService;
    let sut: ExampleSystemUnderTest;

    // ARRANGE
    beforeEach(() => {
        log = jasmine.createSpyObj('log', ['info', 'error']);
        sut = new ExampleSystemUnderTest(log);
    });

    it('should do', () => {
        // ACT
        sut.doIt();

        // ASSERT
        expect(asSpy(log.error)).not.toHaveBeenCalled();
        expect(asSpy(log.info)).toHaveBeenCalledTimes(1);
        expect(asSpy(log.info).calls.allArgs()).toEqual([
            ['done']
        ]);
    });
});

Прийнята відповідь не складається для мене (жасмин 2.5), але це рішення спрацювало!
Пітер Морріс,

Міні-вдосконалення - todoService: {[key: string]: jasmine.Spy} = jasmine.createSpyObj(...); todoService.anyMethod.and....- не потрібно кожного разу кидати Шпигуна.
Кай

Дякую @Kai, я додав детальну інформацію. Мені потрібно (хотілося?) Розпізнавання типу як основний тип, а не як динамічний об'єкт-шпигун. Я особисто хотів, щоб об'єкт діяв і відчував себе справжнім об'єктом, а потім передавав Шпигуну лише тоді, коли я тестував.
Ерік Суонсон,

3

Кутова 9

Використання jasmine.createSpyObjідеально підходить для тестування компонента, де вводиться проста послуга. Наприклад: скажімо, у моєму HomeComponent у мене є HomeService (введений). Єдиним методом у HomeService є getAddress (). Створюючи тестовий пакет HomeComponent, я можу ініціалізувати компонент і службу як:

describe('Home Component', () => {
    let component: HomeComponent;
    let fixture: ComponentFixture<HomeComponent>;
    let element: DebugElement;
    let homeServiceSpy: any;
    let homeService: any;

    beforeEach(async(() => {
        homeServiceSpy = jasmine.createSpyObj('HomeService', ['getAddress']);

        TestBed.configureTestingModule({
           declarations: [HomeComponent],
           providers: [{ provide: HomeService, useValue: homeServiceSpy }]
        })
        .compileComponents()
        .then(() => {
            fixture = TestBed.createComponent(HomeComponent);
            component = fixture.componentInstance;
            element = fixture.debugElement;
            homeService = TestBed.get(HomeService);
            fixture.detectChanges();
        });
    }));

    it('should be created', () => {
        expect(component).toBeTruthy();
    });

    it("should display home address", () => { 
        homeService.getAddress.and.returnValue(of('1221 Hub Street'));
        fixture.detectChanges();

        const address = element.queryAll(By.css(".address"));

        expect(address[0].nativeNode.innerText).toEqual('1221 Hub Street');
    });
 });

Це простий спосіб перевірити ваш компонент за допомогою jasmine.createSpyObj. Однак, якщо у вашій службі є більш складні логічні методи, я б рекомендував створити mockService замість createSpyObj. Наприклад: providers: [{ provide: HomeService, useValue: MockHomeService }]

Сподіваюся, це допомагає!


0

Спираючись на відповідь @Eric Swanson, я створив краще читабельну та документовану функцію для використання у своїх тестах. Я також додав певну безпеку типу, ввівши параметр як функцію.

Я б порекомендував розмістити цей код десь у загальному тестовому класі, щоб ви могли імпортувати його у кожен тестовий файл, який потребує цього.

/**
 * Transforms the given method into a jasmine spy so that jasmine functions
 * can be called on this method without Typescript throwing an error
 *
 * @example
 * `asSpy(translator.getDefaultLang).and.returnValue(null);`
 * is equal to
 * `(translator.getDefaultLang as jasmine.Spy).and.returnValue(null);`
 *
 * This function will be mostly used in combination with `jasmine.createSpyObj`, when you want
 * to add custom behavior to a by jasmine created method
 * @example
 * `const translator: TranslateService = jasmine.createSpyObj('TranslateService', ['getDefaultLang'])
 * asSpy(translator.getDefaultLang).and.returnValue(null);`
 *
 * @param {() => any} method - The method that should be types as a jasmine Spy
 * @returns {jasmine.Spy} - The newly typed method
 */
export function asSpy(method: () => any): jasmine.Spy {
  return method as jasmine.Spy;
}

Використання буде таким:

import {asSpy} from "location/to/the/method";

const translator: TranslateService = jasmine.createSpyObj('TranslateService', ['getDefaultLang']);
asSpy(translator.getDefaultLang).and.returnValue(null);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.