Mike Sav
Mike Sav

Reputation: 15321

Shallow Testing in Angular - overwriting the template - is this good practice?

I have a bit of a hypothetical question regards overwriting the Template in Angular Unit Tests (if this isn't an appropriate question for here please suggest to close rather than mark it down and I will remove / close the question). Members of my team prefer to overwrite the HTML template when unit testing in Angular, so if I had a test it would look something like this:

describe('MyWhateverComponent', () => {
  let component: MyWhateverComponent;
  let fixture: ComponentFixture<MyWhateverComponent>;
  // lots more things here removed

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [
        MyWhateverComponent
      ],
      schemas: [...],
      imports: [...],
      providers: [...]
    }).overrideTemplate(MyWhateverComponent, '<div>Overridden template</div>')
      .compileComponents();
  }));

The reasons my colleagues seem to like doing this as they say it allows them to test the Component code only (as contained in the .ts file), it prevents us having to mock or include directives and we don't want to test Angular bindings like ngIf, ngFor, ngClass, etc, etc... Good arguments but it seems wrong to me as I think you should test what is rendered in the view as it prevents unexpected behaviour or content. This argument doesn't seem to appease my colleagues, can anyone else suggest or think of other reasons why we shouldn't overwrite a template when Unit Testing our Components in Angular. To me it just feels like the nature of our test doesn't really dealwith our true component. I would assume (as I haven't done any checks) that shallow testing would be quicker to execute another reason to support my colleagues.

Any thoughts or opinions are appreciated in advance.

Upvotes: 1

Views: 1322

Answers (2)

Amit Chigadani
Amit Chigadani

Reputation: 29785

In my opinion, one should not go with overriding the complete template of the component being tested. Mocking the child components is fine, but not the actual component.

Several reasons :

  1. You might be using @ViewChild() in your component, referencing some dom element or child component inside your template. So you would definitely loose this.
  2. I believe, component testing is more about testing the view template (rendering), rather than the implementation or behaviour (methods).
  3. Components are meant to face the user, and they need input from the user. So your tests should concentrate more on getting the inputs from view and testing the output. (Not by calling the method directly and expecting it to have been called)

    ex :

    spyOn(comp, 'calculate');
    comp.calculate();
    expect(comp.calculate).toHaveBeenCalled();
    

Upvotes: 2

user4676340
user4676340

Reputation:

If they want to test only the logic of the components, then they should not use Angular context's (a.k.a. the Test Bed) and simply create a new instance of the component like so :

describe('MyWhateverComponent', () => {
  const component = new MyWhateverComponent(/* injection */);
  it('...', () => {...});
});

As described in the testing guide :

But a component is more than just its class. A component interacts with the DOM and with other components. The class-only tests can tell you about class behavior. They cannot tell you if the component is going to render properly, respond to user input and gestures, or integrate with its parent and child components.

None of the class-only tests above can answer key questions about how the components actually behave on screen.
- Is Lightswitch.clicked() bound to anything such that the user can invoke it?
- Is the Lightswitch.message displayed?
- Can the user actually select the hero displayed by DashboardHeroComponent?
- Is the hero name displayed as expected (i.e, in uppercase)?
- Is the welcome message displayed by the template of WelcomeComponent?

And as a side note, the mocking of a service/component/directive is made only once, so that's not that big to do.

Upvotes: 2

Related Questions