Skip to content

Autospy

Georgi Parlakov edited this page Apr 29, 2020 · 2 revisions

Home

Autospy

The goal of autospy is to spare you the boilerplate of creating a mock (spy in jasmine parlance).

It takes a TS class and creates mocks for all methods in its prototype. It then returns an object with the type that allows it to be used as the original type as well as in .hasBeenCalledWith assertions that require a different shape object.

Example

In this example our UserComponent depends on UserService and we'd like to test that when ngOnInit is called it calls UserService.current() method once.

// user.ts
class UserService {
    current(): User {
        //...
    }
}

// user.component.ts
class UserComponent {
    constructor(private user: User) {}

    ngOnInit(){
        this.current = this.user.current();
    }
}

For that, we would need to instantiate the dependency UserService, the component-under-test UserComponent and call the ngOnInit method in our test file:

//user.component.spec.ts

it('calls current', () => {
    // arrange
    const userSpy = autoSpy(UserService);
    // used as the UserService type here     👇
    const userComponent = new UserComponent(userSpy);
    // act
    userComponent.ngOnInit();
    // assert
    //used as the spy-able type here 👇
    expect(userSpy.current).toHaveBeenCalledTimes(1);
    // i.e.👆userSpy has👆current property that can be spied upon
})

Properties

Autospy does not, and (currently) can not create spies for the properties of a class. That's because properties are not part of the prototype and run-time autospy code has no way of detecting them. What to do then? We can assign values to these properties just as we would in our code.

Continuing the example from above:

// user.ts
class UserService {
    // 👇 our dependency has a property - not visible in the prototype, though
    isAuthenticated: boolean;

    current(): User {
        //...
    }
}

// user.component.ts
class UserComponent {
    constructor(private user: User) {}

    ngOnInit(){
        this.current = this.user.current();
        if(this.user.isAuthenticated) {
            this.content = userAuthenticatedContent;
        }
    }
}

For that, we would need to instantiate the dependency UserService, the component-under-test UserComponent and call the ngOnInit method in our test file:

//user.component.spec.ts

it('shows the authenticated user content', () => {
    // arrange
    const userSpy = autoSpy(UserService);
    // set the property 👇 here
    userSpy.isAuthenticated = true;
    const userComponent = new UserComponent(userSpy);
    const authContent = 'This user is indeed authenticated!'
    // act
    userComponent.ngOnInit();
    // assert
    expect(userComponent.content).toEqual(authContent);
})
Clone this wiki locally