2

When using the TestBed, are you really unit testing a component or are you making integration tests?

Creating a fixture (TestBed.createComponent(AppComponent)) and calling fixture.detectChanges() automatically calls ngOnInit. If you want to test another method, you are now testing multiple units.

This leads to another question: should you be testing units, or should you be testing user actions? For example, should you be testing the method setDimensions or should you be testing that when the user clicks on a certain button, an element has the appropriate dimensions amongst other things.

I guess the first way of testing would be closer to the "unit test" way, but then you still have to deal with the lifecycle methods of the component being called. This makes me think there is no way to do unit tests of a component using TestBed. Stubbing all lifecycle methods seems ridiculous.

Whichever way you decide to test, you should also test the DOM, should you not? Then you are not testing in isolation by including the DOM api.

maximedupre
  • 3,597
  • 4
  • 24
  • 56
  • You should consider this before calling everything that includes related components an "integration test" https://stackoverflow.com/a/5357837/4793951 – Zircon May 22 '18 at 20:05
  • I'm not certain that an integration tests should necessarily involve external parts of a system (e.g. DB) as opposed to a unit test. This comment on the answer you pointed me to reflects my thought: "The description of unit testing is very good but have you considered that pairwise integration does not cover whole applications just two testable units". So then are you saying that a test as described in my question, using `TestBed` an asserting the DOM is a unit test, or that perhaps there is a gray line between unit and integration tests and that it could be considered either one of them? – maximedupre May 22 '18 at 20:12

2 Answers2

1

As quoted from Angular docs:

A component, unlike all other parts of an Angular application, combines an HTML template and a TypeScript class. The component truly is the template and the class working together. and to adequately test a component, you should test that they work together as intended.

Such tests require creating the component's host element in the browser DOM, as Angular does, and investigating the component class's interaction with the DOM as described by its template.

The Angular TestBed facilitates this kind of testing as you'll see in the sections below. But in many cases, testing the component class alone, without DOM involvement, can validate much of the component's behavior in an easier, more obvious way.

So here, the unit is a component(the template and the class working together). And you should try to test a component by stubbing the inputs and dependencies.

I guess if you read the testing docs once from top to bottom, you have answers for your questions in there.

sabithpocker
  • 14,235
  • 1
  • 36
  • 69
  • An integration test is supposed to test that different parts of an application are working together, so one could argue that testing a component (which is a combination of a class and a template/DOM) is in fact an integration test. Can you really say a test is a unit test because a single unit is being tested? Aren't unit tests supposed to test the smallest possible unit? A component is definitely not the smallest unit. So then are the unit's size/scope subjective? What is a unit? Is a module a unit? – maximedupre May 22 '18 at 22:27
  • Yes, a module is a unit in certain cases. Whether a test is unit or integration is better understood by looking at the *rationale of the test* rather than the size or complexity of the unit, ie if the focus of the test is on the functionality of a unit or the message passing between units. I guess you are stuck with the idea of **pure functions** being the only possible legitimate **unit** for testing. Take a look at [how wikipedia tries to define units covering different possibilities](https://en.wikipedia.org/wiki/Unit_testing) – sabithpocker May 23 '18 at 09:37
  • Thank you for your response, I read the Wikipedia article. If a module can be a unit and a component can be a unit (which is part of a module), then testing a module with the objective of verifying it's functionality would also test the message passing between components (also units). So if you are not testing the smallest unit, you will always be testing the communication between smaller units. – maximedupre May 23 '18 at 16:25
  • I guess considering modules as units is in different programming languages other than JavaScript where it is trivial to make that choice. Not something applicable to Angular modules. – sabithpocker May 24 '18 at 06:30
0

Here's more information, gathered from the Test Driven Development Wikipedia page.

For TDD, a unit is most commonly defined as a class, or a group of related functions often called a module. Keeping units relatively small is claimed to provide critical benefits [...]

So unit testing does not necessarily test the smallest unit possible.

Test-driven development does not perform sufficient testing in situations where full functional tests are required to determine success or failure, due to extensive use of unit tests.[21] Examples of these are user interfaces, programs that work with databases, and some that depend on specific network configurations. TDD encourages developers to put the minimum amount of code into such modules and to maximize the logic that is in testable library code, using fakes and mocks to represent the outside world.[22]

UI is testable by unit tests until a certain point of diminishing returns, which is when functional tests/e2e tests are useful.

Unit tests are so named because they each test one unit of code. A complex module may have a thousand unit tests and a simple module may have only ten. The unit tests used for TDD should never cross process boundaries in a program, let alone network connections. Doing so introduces delays that make tests run slowly and discourage developers from running the whole suite. Introducing dependencies on external modules or data also turns unit tests into integration tests. If one module misbehaves in a chain of interrelated modules, it is not so immediately clear where to look for the cause of the failure.

I think I would now define integration tests as tests that also test external parts of the application, such as other processes like a DB or a server API.

maximedupre
  • 3,597
  • 4
  • 24
  • 56