繁体   English   中英

如何存根茉莉花模拟对象的方法?

[英]How to stub a method of jasmine mock object?

根据 Jasmine 文档,可以像这样创建模拟:

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

你如何存根这些方法之一? 例如,如果你想测试当一个方法抛出异常时会发生什么,你会怎么做?

您必须像 EricG 评论的那样链接method1method2 ,但不能使用andCallThrough() (或版本 2.0 中的and.callThrough() )。 它将委托给真正的实施

在这种情况下,您需要链接and.callFake()并传递您想要调用的函数(可以抛出异常或任何您想要的):

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

然后你可以验证:

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

如果您使用的是 Typescript,将方法转换为Jasmine.Spy 在上面的答案中(奇怪的是我没有代表发表评论):

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

我不知道我是否过度设计,因为我缺乏知识......

对于打字稿,我想要:

  • 来自底层类型的 Intellisense
  • 仅模拟函数中使用的方法的能力

我发现这很有用:

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']
        ]);
    });
});

角度 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 }]

希望这可以帮助!

在@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);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM