1

I need to spy on the public property in angular service. But this property doesn't have getter or setter, therefore, I couldn't spy on that property.

Always get or set is required to use that SpyOn. If I don't provide it, it is set as 'get'. Is there any other way to mock or spy on public property without getter or setter? And why are those methods not available? Am I using an anti-pattern by exposing a public property from service?

This is the code with the public variable that I need to mock:

@Injectable()
export class StudentService {

  public students = [];
  .................

}
mkrieger1
  • 19,194
  • 5
  • 54
  • 65
PushpikaWan
  • 2,437
  • 3
  • 14
  • 23
  • Is there a reason that you do not mock the whole service away? It seems your test would currently test your code plus the service. If you mock the service away, the mock can contain getter/setter. – JanRecker Apr 01 '20 at 15:53
  • @JanRecker Yes I'm mocking server there. using spy. Then we need to spy on properties as well. Do u have another way to mock service instead of spy on that? – PushpikaWan Apr 01 '20 at 16:05
  • in your case (with a non global service) add in the testBed setup, in provide: [{provide:StudentService, class: MyMockService}. Then it will use MyMockService instead of StudentService. Be aware that your mock has to provide the same interface (public methods variable) as the StudentService (as long as you use them). But they could be implemented differently – JanRecker Apr 02 '20 at 06:50
  • @JanRecker If I use a mock class and mock the getter to return a value of my choice, do I have the ability to change what the getter returns inside each test case? I want to test different code paths based on the property of the injected service. – SOUPTIK BANERJEE Sep 16 '20 at 14:43
  • @SOUPTIK BANERJEE - Your mock object is an object of your will. It must have the same interface as the original object it should mock (at least for the used methodes/variables) but the code behind those interfaces is yours. So you could add additional methods and change the behavior of your mock object through them. Or if you use JEST, JASMINE or a similar framework, they all provide mock creators which can easily change the behavior of the mocked objects any time. – JanRecker Sep 17 '20 at 16:01

2 Answers2

0

You don't need to spy on separate properties, because they don't contain any business logic. One of the purposes of testing is to ensure that functionality works as desired. So you really need to test only methods, and in some cases check on how they affect your properties, e.g. expect(component.students).equaltTo(mockStudents2).

Oleksii
  • 56
  • 3
  • that's ok. But I used that student object for other processes. Therefore I need to mock that and provide value to do other tests – PushpikaWan Apr 01 '20 at 16:07
  • If I understood you correctly, you can just initialize it in `beforeEach` with some mock data `component.students = mockStudents`, `mockStudents` you can store as constant in a separate file, e.g. mocks.ts. – Oleksii Apr 01 '20 at 16:12
0

I would use jasmine.createSpyObj and then attach it to this object.

Try:

describe('Your component test', () => {
  let mockStudentService: any;

  beforeEach(async(() => {
    mockStudentService = jasmine.createSpyObj('studentService', []); 
    // in the empty array put the public methods you require as strings
    mockStudentService.students = []; // mock the public array you want here
    TestBed.configureTestingModule({
      providers: [{ provide: StudentService, useValue: mockStudentService }],
    }).compileComponents();
  }));
});
AliF50
  • 16,947
  • 1
  • 21
  • 37