0

I am writing a Unit test for a class which extends another class and call parent method at runtime. Since I don't want to deal with parent class is there any way to mock that method call ? I have tried multiple ways but nothing in working

class A {
   doSomething(){
       console.log(123);
     }
}

class B extends A {
    work(){
      this.doSomething();
  }
}

How I can mock this function call and return something else in Unit Test for Class B ?

I have tried the following :

spyOn(b,'doSomething');

spyOn(Object.getPrototypeOf(b),'doSomething');

There are no errors it just keeps calling the original parent method

2
  • It would be nice to show us, what exactly you have tried so far and what the specific errors where. Commented Sep 10, 2020 at 6:12
  • Updated @Erbsenkoenig Commented Sep 10, 2020 at 6:19

1 Answer 1

1

What you could do, but I would not recommend it, is to stub the parent method itself inside you class B.

I would not recommend this approach because you would stub something inside the Class you are unit testing. I would rather stub things, that are being done inside this parent method.

But if you really want to stub that method, you could do something along those lines:

describe('DataService', () => {
    let service: DataService;

    beforeEach(async(() => {
      TestBed.configureTestingModule({ providers: [DataService] });
    }));

    beforeEach(() => {
      service = TestBed.get(DataService); // would be inject in newer angular versions
    });

    it('test case 2', () => {
      spyOn(service as any, 'parentMethod').and.returnValue(5);
      expect(service.getData()).toEqual(5);
    });
});

where DataService would be


@Injectable({
  providedIn: 'root'
})
export class DataService extends AbstractDataService {
  constructor() {
    super();
   }

  getData() {
    return this.parentMethod();
  }
}

and AbstractDataService

@Injectable({
  providedIn: 'root'
})
export class AbstractDataService {
  constructor() { }

  parentMethod() {
    console.log('parent method');
    return null;
  }
}

Works for components, too. But again: it is not advisable to mock methods inside the object under test!!

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

    beforeEach(async(() => {
        TestBed.configureTestingModule({
            declarations: [AppComponent, AbstractAppComponent],
            schemas: [NO_ERRORS_SCHEMA],
            bootstrap: [AppComponent]
        }).compileComponents();
    }));

    beforeEach(() => {
        fixture = TestBed.createComponent(AppComponent);
        component = fixture.componentInstance;
    });

    it('should mock method', () => {
      spyOn(component as any, 'abstractMethod').and.returnValue(10);

      fixture.detectChanges();
      expect(component.myMethod()).toEqual(10);
    });    
});

Stackblitz with test cases for both service and component

Sign up to request clarification or add additional context in comments.

10 Comments

makes sense, but the only difference is in my case its a Component not a service. And this approach doesn't work when you try to stub a method from the parent class of a component. Can you help with that ?
it works the same way. instead of spying on the service you will spy on the method inside your component.
service = TestBed.get(DataService); this won't work for component. I have tried spyOn(component,'parentMethod'); but it call the original method only
When you work with a TestBed, you will get your component instance. And you can stub methods on that, just like on you services
Have a look at the stackblitz, i've included a component version.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.