Search code examples
angularunit-testingservicejasmine

Jasmine Unit Test, override only property in service


this is my component spec file. It uses CalendarService. Inside CalendarService there are weekNames,monthNames,monthLongNames properties(which are just arrays of strings). Now... CalendarService has a lot of methods inside it. I want to be able to override only these 3 properties in my spec file but keep the rest of the methods and use them in the spec file. The reason why I want to override them is because they use another service to be created(e.g. weekNames = [this.translationService.formatMessage(), ... , ... , ...]). Which makes testing very difficult having a component with a service that has a service inside it.

EDIT: or another solution would be to override the translationservice with a mockservice. However translationservice is located inside CalendarService which uses my component. So i dont know how to do that.

describe('FCCalendarComponent', () => {
    let component: CalendarWrapperComponent;
    let fixture: ComponentFixture<CalendarWrapperComponent>;

    let calendarComponent: FCCalendarComponent;

    beforeEach(waitForAsync(() => {
        TestBed.configureTestingModule({
            declarations: [
                FCCalendarComponent,
                CalendarWrapperComponent
            ],
            imports: [
                BrowserModule,
                FormsModule,
                ReactiveFormsModule,
                FCBaseModule,
                HttpClientModule,
                FCTranslateModule,
                FCCalendarModule
            ],
            providers: [
                FCTranslateLoader,
                CalendarService,
                FCTranslationService,
                {
                    provider: CalendarService, useValue: {
                        weekNames: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
                        monthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
                        monthLongNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
                    }
                },
            ]
        }).compileComponents();
    }));

    beforeEach(() => {
        fixture = TestBed.createComponent(CalendarWrapperComponent);
        component = fixture.componentInstance;
        calendarComponent = fixture.debugElement.children[0].componentInstance;
        fixture.detectChanges();
    })


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



@Component({
    selector: 'calendar-wrapper',
    template: `
        <fc-calendar value="2001.02.02" 
            minDate="2000.03.03" 
            maxDate="2002.04.04">
        </fc-calendar>
    `
})
export class CalendarWrapperComponent {

}

Solution

  • SOLUTION: If you have a service in your component and that service has another service used inside it. Instead of mocking the 'parent' service, you can mock the 'child' service. Simply by adding 'child' service to providers like so

    FCTranslationService,
    {
        provider: FCTranslationService, useValue: { }
    },
    

    and in beforEach overriding it with your mock service, like so

    TestBed.overrideProvider(FCTranslationService, { useValue: new TranslateMockService() })
    

    and in case you wanna know what mock looks like.

    export class TranslateMockService {
        formatMessage() {
            return;
        }
    }
    

    The mock only has the method which is being used by the parent service and nothing else.