Unit Testing

March 2019 State

Agenda

Preparation

https://github.com/devonfw-ng-adv-training/defonfw-testing

Why unit tests?

  • recognize bad component design
  • easy to refactor application
  • implement new features without breaking old ones

Basics / jasmine

  • suites: describe(string, function)
  • specs: it(string, function)
  • expectations: expect(actual)...
  • matchers: toBe(expected), toEqual(expected)...

.. / setup & teardown

  • beforeAll
  • beforeEach
  • afterEach
  • afterAll

Mocking Child Components?

  • more isolated testing
  • strongly typed template checking
  • less coupling between components and services
  • prefer dumb components over smart components

Child Components / declarations

  • Use real component
  • Use NO_ERRORS_SCHEMA
  • Mock component
  • use mocking framework like ng-mocks

Testing asynchronous code

  • async
  • fakeAsync
  • done

async


it('should show quote after getQuote (async)', async(() => {
  fixture.detectChanges(); // ngOnInit()
  expect(quoteEl.textContent).toBe('...', 'should show placeholder');

  fixture.whenStable().then(() => { // wait for async getQuote
    fixture.detectChanges();        // update view with quote
    expect(quoteEl.textContent).toBe(testQuote);
    expect(errorMessage()).toBeNull('should not show error');
  });
}));
            
https://angular.io/guide/testing#async-test-with-async

fakeAsync


it('Button label via fakeAsync() and tick()', fakeAsync(() => {
  expect(el.nativeElement.textContent.trim()).toBe('');
  fixture.detectChanges();
  expect(el.nativeElement.textContent.trim()).toBe('Login');
  spyOn(authService, 'isAuthenticated').and
                    .returnValue(Promise.resolve(true));
  component.ngOnInit();

  tick();
  fixture.detectChanges();
  expect(el.nativeElement.textContent.trim()).toBe('Logout');
}));
            
https://angular.io/guide/testing#async-test-with-fakeasync

done


it('should show last quote (quote done)', (done: DoneFn) => {
  fixture.detectChanges();

  component.quote.pipe( last() ).subscribe(() => {
    fixture.detectChanges(); // update view with quote
    expect(quoteEl.textContent).toBe(testQuote);
    expect(errorMessage()).toBeNull('should not show error');
    done();
  });
});
            
https://angular.io/guide/testing#jasmine-done

consumer-driven contract testing

  • consumer defines requirements
  • for an api of provider
  • via tests
  • generate contract via pact
  • provider tests all contract files in build pipeline

pact / interface

pact / consumer

pact / provider

consumer code (java spring)


@RunWith(SpringRestPactRunner.class)
@Provider("book-service")
@PactFolder("pacts")
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class ContractTest {

  @TestTarget
  public final Target target = new SpringBootHttpTarget();

  @State("Books exist")
  public void user1Exists() {
    // nothing to do, real service is used
  }
}