We all know what unit tests are and how important they are for the success of a project. Yet, it’s still common to hear people say they aren’t that helpful or that they don’t need them.

I get it. No one likes to write unit tests. But if we don’t write unit tests, it leads to technical debt. And like all debt, you occur ‘interest’.

You may be asking what this interest is? Well, to explain, let’s start off with a reminder of what a unit test is.

A unit test is an automated test meant to ensure that a small section of your code meets its intended design and behavior.

Your test should be a reflection of the requirements of your implementation, regardless if you wrote your test before or after implementation. In this article, I will be focusing on why deferring writing tests until later is not such a great idea.

 

Common Scenarios

Now I can probably tell what you’re thinking, “if I have the requirements still in the cloud I can always go back and write the tests.”

This sounds great in theory, but reality tends to have a different result.

During implementation, the developer understands the requirements as best as they can while the requirements are still fresh in their minds; this is when they are most up to date with what’s needed for the feature. (I’m sure I’m not the only one that has experienced last-minute updates to the requirements.)

It’s also definitely possible that those updates don’t get documented. Imagine a developer trying to write a test with a set of requirements that don’t match. This turns into a ‘chicken and egg’ scenario: are the requirements wrong or is the implementation wrong?

Not documenting changes is a separate problem itself but having a developer who understands the requirements and writes tests is another safeguard. It is another point in time for the validation of the requirements. Whether it’s the same or a different developer writing the tests, someone will be verifying that the requirements match the implementation.

Of course, you can work out any discrepancies by getting people together to discuss the problem. However, this leads to more overhead which could involve the original dev, the dev writing the test, a business analyst who worked on the problem, and any other people required to resolve the issue. I think you can start to see my point here.

Rather than taking the time to write the tests, we made technical debt which has increased the effort by a much larger magnitude.

Deferring writing the tests, in general, will take longer because the developer (even the original developer) will have to familiarize themselves with the requirements, even if the requirements are 100% up to date.

 

What Happens When Tests Are Ignored?

It sounds like I have been talking in hypotheticals, but I have worked on projects where tests were put aside for sake of velocity.

What happens when tests are ignored? Well, they fail and don’t build properly. This means that you cannot include a test run as part of your CI (continuous integration) build.

Now an x number of months come along and the project has died down, and there’s some capacity for tests. You run your Angular tests with an “ng test” command and are greeted with an everlasting list of build errors. You will have to, at the minimum, fix all the build errors if you want to include a test step as part of your CI build.

This list of errors may seem daunting and you may be wondering, “how did it get this bad don’t all the auto-generated tests pass by default?”

Yes, Angular provides a default spec file that varies depending on what is generated. While this test passes in Angular at first on creation, as your Angular implementation becomes more complex with dependencies, the default tests will no longer pass.

Rather than dealing with all the messages at once, I like to tackle the first build error I find. I’ll run it in isolation and fix any build errors.

 

Running Tests

To run one test, you can prefix your “describe” with an ‘f’. You can use the same ‘f’ prefix for individual tests like so “fit”.

The next step is to fix the test bed setup for your test. Each test could have different dependencies. Most of the time a module needs to be imported, or a provider may need to be added. You can look at the code sample and see that the test bed needs to import the dependent modules and provide the SampleToken. If we remove any of these dependencies, you can see the error messages appear in the terminal. I like to work through these errors that appear in the terminal one at a time until the test passes.

describe('TestComponent', () => {
  let component: TestComponent;
  let fixture: ComponentFixture;
 
  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [SharedModule, MatSnackBarModule, NoopAnimationsModule],
      providers: [
        {
          provide: SAMPLE_TOKEN,
          useValue: 'Test'
        }
      ],
      declarations: [ TestComponent ]
    })
    .compileComponents();
  });
 
  beforeEach(() => {
    fixture = TestBed.createComponent(TestComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });
 
  it('should create', () => {
    expect(component).toBeTruthy();
  });
});

The other thing to consider are dependencies in your html template. If you’re using any libraries and any components, you will have to make sure you import the required modules from the library into the testbed. For example, in order to make use of the mat-card component, I need to import the MatCardModule.

Once this test is in a runnable state, make sure to remove any ‘f’ prefixes before moving on to other tests. You can follow the same steps and work through your build errors and failing tests.

These steps are doing the bare minimum to get your default “it exists” tests to pass. Once you start writing tests you will be able to do more fun things like creating spies, providing mocked services, intercepting http requests and the list goes on. You may even need to fix your dependencies again once your angular test is starting to go through the paces.

As you continue your journey with testing there will be other complexities and advanced setup that are needed depending on the situation. While most of this content is available on Angular’s official site, Imaginet has the experience and technical know-how to get you through any more difficult scenarios.

Need help?

Since 1997, Imaginet has helped organizations create and reinvent their business web applications to empower their workforce and propel productivity. Find out more about what makes Imaginet different and how our consultants can help.

 

Learn more

Charles Ung

About Charles Ung

Charles is an experienced software developer and consultant with a B.Sc. Computer Science and over 5 years of experience. He has an extensive background in web development, unit testing, database implementation, UX design and team mentorship.

Let‘s Talk.
  • Let's Talk

  • This field is for validation purposes and should be left unchanged.