DDD Building Blocks – Value Objects

Value objects are one of the foundational building blocks of Domain-Driven Design. They allow modelling concepts of the Ubiquitous Language that describe, measure or quantify other things in the domain.

It is crucial to understand their characteristics and make more use of them whenever possible instead of trying to model every concept as an Entity or worse, having an Anemic Domain Model where logic related to a value leaks and spreads around services or client code. Values help separating concerns and they are easier to implement, test and maintain.

Examples of Value Objects in a domain could be colour, money, address, e-mail, coordinate, etc. Note that a concept can be an Entity in one domain model and a Value Object in other.

Value Object Characteristics

– Inmutable Conceptual Whole
– Describes, Measures or Quantifies an Entity
– Does not have a unique identity
– Structural equality
– Replaceability
– Side-Effect-Free Behaviour

Implementing Value Objects

Constructors

Value objects are inmutable, do not implement setter methods for its properties, instead provide a constructor with all parameters necessary to initialize its intrinsic state. Parameters may be other objects used to derive internal properties on the new Value.

public class Money {
    private BigDecimal amount;
    private String currency;

    public Money(BigDecimal amount, String currency) {
        this.amount = amount;
        this.currency = currency;
    }

    public BigDecimal getAmount() {
        return amount;
    }

    public String getCurrency() {
        return currency;
    }
...

You can find useful, especially for testing immutability, to provide a copy constructor.

    public Money(Money money) {
        this.amount = money.amount;
        this.currency = money.currency;
    }

Use Guard Clauses in the constructor to ensure that the parameters passed are not only valid individually also as a whole initialize a valid Value.

public class FullName {
    private String firstName;
    private String lastName;

    public FullName(String firstName, String lastName) {
        if (firstName == null || lastName == null) {
            throw new IllegalArgumentException("First and last name are required.");
        }

        this.firstName = firstName;
        this.lastName = lastName;
    }
...

Self-encapsulation/delegation

Value objects must not expose setter methods, but internally, we may use and delegate to them to simplify constructors.

Continue reading “DDD Building Blocks – Value Objects”

Advertisements

Developing with a Stub backend on Angular 2

In Angular 1 I always use during development a stub or mock REST API backend that allows me running the application without the real API. In this way, the front-end implementation can be started before or in parallel with the backend. It is also useful for small prototypes or demos.

You could quickly implement a fake backend using Node or something similar, but I recommend to mock the backend directly in Angular. It is faster because the application won’t hit the wire and what I really like is that it is stateless (every time the browser is reloaded the stub data is reinitialized).

Those two points are great for local development but what I find fundamental is to use it for running protractor E2E tests, that way I always can rely on a backend substitute that does not keep state between test (protractor reloads the browser before every test, and again the stub data gets reinitialized).

This post shows how to configure a stub backend on Angular 2 using the MockBackend test class.
On develop mode we will override the Http provider to, instead of using a real backend implementation such as XHRBackend, use the MockBackend.

I define the stub backend provider in a separate file stub-backend-provider.ts, here is all the magic happens swapping the backend provider for develop mode and defining stub responses for determined HTTP requests.

src/app/stub-backed/stub-backend-provider.ts

import { Http, BaseRequestOptions, Response, ResponseOptions, RequestMethod, XHRBackend } from '@angular/http';
import { MockBackend, MockConnection } from '@angular/http/testing';

import { environment } from '../../environments/environment';
import { Task } from '../tasks-list/task';
import { generateUuid, getUuidFromUrl } from './stub-backend-utils';

/**
 * Provider to allow the use of a stub backend instead of a real Http service for backend-less development.
 */
export let stubBackendProvider = {
  provide: Http,
  deps: [MockBackend, BaseRequestOptions, XHRBackend],
  useFactory: (mockBackend: MockBackend, options: BaseRequestOptions, realBackend: XHRBackend) => {

    if (!environment.stubBackend) {
      console.log('Configuring real Http backend...');
      return new Http(realBackend, options);
    }

    console.log('Configuring stub Http backend...');

    let tasks: Task[] = [
      {id: '9509c8b4-ad34-4378-b49c-c9206dfd7f75', name: 'Buy milk', done: false, userId: 'user-1'},
      {id: '1b35d8f8-9e80-4316-b3e3-135a8f81200f', name: 'Pay rent', done: true, userId: 'user-1'}];

    mockBackend.connections.subscribe((connection: MockConnection) => {

      // wrap in timeout to simulate server api call
      setTimeout(() => {

        // Get all tasks
        if (connection.request.method === RequestMethod.Get && connection.request.url.match('/tasks$')) {
          connection.mockRespond(new Response(new ResponseOptions({body: tasks.slice()})));
          return;
        }

        // Save task
        if (connection.request.method === RequestMethod.Post && connection.request.url.match('/tasks$')) {
          let newTask = JSON.parse(connection.request.getBody());
          newTask.id = generateUuid();
          tasks.push(newTask);

          connection.mockRespond(new Response(new ResponseOptions({body: newTask})));
          return;
        }

        // Delete task
        if (connection.request.method === RequestMethod.Delete && connection.request.url.match('/tasks/*')) {
          let id = getUuidFromUrl(connection.request.url);
          tasks = tasks.filter(task => task.id !== id);

          connection.mockRespond(new Response(new ResponseOptions()));
          return;
        }
      }, 500);

    });

    return new Http(mockBackend, options);
  }
};

The provider requires uses a new Angular CLI environment property that I called stubBackend, with a value of true on develop and false on production.
/src/environments/environment.ts

export const environment = {
  production: false,
  stubBackend: true
};

/src/environments/environment.prod.ts

export const environment = {
  production: false,
  stubBackend: false
};

Continue reading “Developing with a Stub backend on Angular 2”

Unit test exception messages using JUnit ExpectedException Rule

Traditionally JUnit supported expected exceptions using the @Test annotation like this

@Test(expected = ParsingException.class)
public void parseGame_when_fileIsEmpty_then_throwsParsingException() throws Exception {
   // Arrange
   BufferedReader bufferedReaderMock = mock(BufferedReader.class);
   when(bufferedReaderMock.readLine()).thenReturn("");

   // Act
   gameJsonParser.parseGame(bufferedReaderMock);
}

This has two inconveniences. The expectation should be defined outside the test body and it does not support asserting the exception message.

A workaround commonly used is handling the exception with a try/catch block and assert it manually.

@Test
public void parseGame_when_fileIsEmpty_then_throwsParsingException() throws Exception {
   // Arrange
   BufferedReader bufferedReaderMock = mock(BufferedReader.class);
   when(bufferedReaderMock.readLine()).thenReturn("");

   // Act
   try {
     gameJsonParser.parseGame(bufferedReaderMock);
     fail("Should have thrown ParsingException but did not!");
   }
   catch(ParsingException e) {
     String message = "Parsing failed. Empty game file.";
     assertEquals(message, e.getMessage());
   }
}

As you can see that brings lot of boilerplate code to the test.

Since JUnit 4.7 we can use the ExpectedException core rule to assert exceptions in a more natural flow and also to assert their messages.

ExpectedException: Allows a test to specify expected exception types and messages in the test itself.

@Rule
public ExpectedException exception = ExpectedException.none();

@Test
public void parseGame_when_fileIsEmpty_then_throwsParsingException() throws Exception {
   // Arrange
   BufferedReader bufferedReaderMock = mock(BufferedReader.class);
   when(bufferedReaderMock.readLine()).thenReturn("");

   exception.expect(ParsingException.class);
   exception.expectMessage("Parsing failed. Empty game file.");

   // Act
   gameJsonParser.parseGame(bufferedReaderMock);
}

References:
https://paucls.wordpress.com/2013/11/12/using-junit-rules
https://www.infoq.com/news/2009/07/junit-4.7-rules

Unit test Http Services on Angular 2

Angular 2 testing documentation is more than good, but I believe that it is missing a crucial bit. How should we test services that make use of Http?

For example, let’s say that we want to unit test a TasksService with a getTasks method to GET task resources from a REST API.

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import 'rxjs/add/operator/toPromise';
import { Task } from './task';

@Injectable()
export class TasksService {
  private tasksUrl = 'http://a-task-list-api.com/tasks';

  constructor(private http: Http) {}

  getTasks(): Promise<Task[]> {
    return this.http.get(this.tasksUrl)
      .toPromise()
      .then(response => response.json() as Task[]);
  }
}

The service uses angular Http service to perform HTTP requests. Unit test of this service should be done in isolation because we don´t want our service to be hitting the real network and at the same time, we want to control and fake the responses from the API. For that reason, we need to use a mock Http service.

Implementing a fake version of the Http service can get really complicated, the good thing is that Angular 2 already provides one for us, the MockBackend.

This is a full example of unit test using MockBackend and BaseRequestOptions to create a Http mock.

import { TestBed, inject, tick, fakeAsync } from '@angular/core/testing';
import { BaseRequestOptions, Http, ConnectionBackend, Response, ResponseOptions, RequestMethod } from '@angular/http';
import { MockBackend } from '@angular/http/testing';

import { TasksService } from './tasks.service';
import { Task } from './task';

describe('TasksService', () => {

  const TASKS: Task[] = [
    {id: 'task-1', name: 'Buy milk', done: false, userId: 'user-1'},
    {id: 'task-2', name: 'Pay rent', done: true, userId: 'user-1'}
  ];

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [
        {
          provide: Http,
          deps: [MockBackend, BaseRequestOptions]
          useFactory: (backend: ConnectionBackend, defaultOptions: BaseRequestOptions) => {
          return new Http(backend, defaultOptions);
         }
        },
        {provide: MockBackend, useClass: MockBackend},
        {provide: BaseRequestOptions, useClass: BaseRequestOptions},
        {provide: TasksService, useClass: TasksService}
      ]
    });
  });

  describe('getTasks()', () => {

    it('should return all tasks', inject([TasksService, MockBackend], fakeAsync((tasksService: TasksService, mockBackend: MockBackend) => {
      let result;

      mockBackend.connections.subscribe(c => {
        expect(c.request.method).toBe(RequestMethod.Get);
        expect(c.request.url).toBe('http://paucls-task-list-api.herokuapp.com/tasks');
        let response = new ResponseOptions({body: TASKS});
        c.mockRespond(new Response(response));
      });

      tasksService.getTasks().then(tasks => {
        result = tasks;
      });
      tick();

      expect(result.length).toBe(TASKS.length);
    })));

  });

});

As a reference, in Angular 1 we use the $httpBackend service mock.

    describe('getTasks()', function () {
        it('should return all tasks', function () {
            $httpBackend.expectGET('/tasks').respond(TEST_TASKS);

            let tasks = TasksService.getTasks();
            $httpBackend.flush();
            tasks = resolvePromise(tasks, $q, $scope);

            expect(tasks).toEqual(TEST_TASKS);
        });
    });

Documentation:
https://angular.io/docs/ts/latest/guide/testing.html#!#isolated-service-tests
http://gist.asciidoctor.org/?github-mraible%2Fng2-demo%2F%2FREADME.adoc
https://semaphoreci.com/community/tutorials/testing-angular-2-http-services-with-jasmine

Deploy Angular 2 CLI app to Heroku

Angular2 CLI generated apps can’t be directly deployed in Heroku. But it is easy to configure them to do that using scripts to build and serve the app.

I used angular-cli 1.0.0-beta.20-4 to generate and Angular2/Webpack app.
npm install -g angular-cli
ng new ng2-demo-app

And configured the package.json file using heroku-prebuild, heroku-postbuild and start scripts to build the app and serve it using http-server.

"scripts": {
  "heroku-prebuild": "npm install -g http-server",
  "heroku-postbuild": "ng build --prod",
  "start": "http-server dist/",

Heroku-prebuild and heroku-postbuild are Heroku-specific build steps, they are equivalent to the generic preinstall or postinstall but using them we avoid running those scripts locally.

In Heroku dev-dependencies are not installed by default, that means that to make the ng build script to work we need to move dev-dependency to the dependencies block.

"dependencies": {
  "@angular/common": "~2.1.0",
  "@angular/compiler": "~2.1.0",
  "@angular/core": "~2.1.0",
  "@angular/forms": "~2.1.0",
  "@angular/http": "~2.1.0",
  "@angular/platform-browser": "~2.1.0",
  "@angular/platform-browser-dynamic": "~2.1.0",
  "@angular/router": "~3.1.0",
  "core-js": "~2.4.1",
  "rxjs": "5.0.0-beta.12",
  "ts-helpers": "~1.1.1",
  "zone.js": "~0.6.23",

  // moved here these devDependencies
  "angular-cli": "1.0.0-beta.20-4",
  "@angular/compiler-cli": "~2.1.0",
  "@types/jasmine": "~2.2.30",
  "@types/node": "~6.0.42",
  "typescript": "~2.0.3"
},
"devDependencies": {
  "codelyzer": "~1.0.0-beta.3",
  "jasmine-core": "2.4.1",
  "jasmine-spec-reporter": "2.5.0",
  "karma": "1.2.0",
  "karma-chrome-launcher": "~2.0.0",
  "karma-cli": "~1.0.1",
  "karma-jasmine": "~1.0.2",
  "karma-remap-istanbul": "~0.2.1",
  "protractor": "4.0.9",
  "ts-node": "1.2.1",
  "tslint": "3.13.0",
  "webdriver-manager": "10.2.5"
}

Notice that it’s preferable to move only the dependencies you actually need for production builds. For that reason I moved only the dependencies required for the build but not the testing or linting dependencies.

If you don’t want to be moving dependencies it is possible to disable the production mode in the Heroku instance with
heroku config:set NPM_CONFIG_PRODUCTION=false
With this Heroku will install all dependencies, included the dev ones.

Another alternative to the http-server solution explained here is to use the NGINX and Heroku-buildpack-static.

Docs:
https://www.angularonrails.com/deploy-angular-cli-webpack-project-heroku/
https://github.com/angular/angular-cli/issues/2517
https://m.alphasights.com/using-nginx-on-heroku-to-serve-single-page-apps-and-avoid-cors-5d013b171a45#.1zpyh4lao
https://github.com/heroku/heroku-buildpack-static

Jasmine-Matchers – Adding more common matchers to Jasmine.

Jasmine-Matchers is a library of test assertion matchers for a range of common use-cases, to improve the readability of tests written using the Jasmine testing framework.

Installation

Install the package

npm install karma-jasmine-matchers --save-dev

And configure it in karma.conf in the frameworks section

frameworks: ['jasmine', 'jasmine-matchers’],

To use the additional matchers also in protractor e2e, protractor should be configured to import the ‘jasmine-expect’ module before the tests run. That can be done in the protractor.conf.js like this:

onPrepare: function () {
// Import additional jasmine matchers
require('jasmine-expect’);
}

Usage

The list of additional matchers is available here https://github.com/JamieMason/Jasmine-Matchers#matchers

Examples

Examples of unit test refactors using new matchers

toBeArrayOfSize
– expect(clients.length).toBe(2);
+ expect(clients).toBeArrayOfSize(2);

and instead of failing like this
Expected 1 to be 2.
when it fails, the new matcher look like this:
Expected [ Object({ id: ‘client-id’, name: ‘A Client’ }) ] to be array of size 2.

toBeEmptyString
– expect(vm.getCategory({})).toBe(‘’);
Expected ‘Test’ to be ‘’
+ expect(vm.getCategory({})).toBeEmptyString();
Expected ‘Test’ to be empty string.

– expect(vm.projectsFilter.name).toEqual(‘’);
Expected ‘Test’ to be ‘’
+ expect(vm.projectsFilter.name).toBeEmptyString();;
Expected ‘Test’ to be empty string.

toBeEmptyObject
– expect(data).toEqual({});
Expected Object({ location: ‘ftp.mysite.com’, username: ‘username’, password: ‘password’, directory: ‘test’ }) to equal Object({ }).
+ expect(data).toBeEmptyObject();
Expected Object({ location: ‘ftp.mysite.com’, username: ‘username’, password: ‘password’, directory: ‘test’ }) to be empty object.

toBeTrue
– expect(vm.showHelp).toBe(true);
Expected false to be true.
+ expect(vm.showHelp).toBeTrue();
Expected false to be true.

Documentation

https://github.com/JamieMason/Jasmine-Matchers
https://www.npmjs.com/package/karma-jasmine-matchers
https://blog.pivotal.io/labs/labs/writing-beautiful-specs-jasmine-custom-matchers
https://github.com/JamieMason/Jasmine-Matchers/issues/60

Decorating Angular $httpBackend service.

An example of how to ​decorate the angular $httpBackend mock server with custom logic. In this example, I log to console the request method and URL.

// Configure the Mock HTTP Backend
angular
    .module('my-app')
    .config(['$provide', function ($provide) {
        $provide.decorator('$httpBackend', angular.mock.e2e.$httpBackendDecorator);
    }]);

// Decorate Mock HTTP Backend to log requests
angular
    .module('my-app')
    .config(function ($provide) {
        $provide.decorator('$httpBackend', function ($delegate) {
            let decoratedHttpBackend = function (method, url, data, callback, headers, timeout, withCredentials, responseType) {
                console.log(method + ' ' + url);

                return $delegate.call(this, method, url, data, callback, headers, timeout, withCredentials, responseType);
            };

            for (var key in $delegate) {
                if ($delegate.hasOwnProperty(key)) {
                    decoratedHttpBackend[key] = $delegate[key];
                }
            }

            return decoratedHttpBackend;
        });
    });