-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathchap8.tex
106 lines (83 loc) · 6.66 KB
/
chap8.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
\chapter{Testing}
\label{chap:testing}
This chapter contains a description of how \ac{TDD} is applied to this project.
Considering testing as equal in importance to application writing makes the code to be more robust, lowers the cost of maintenance and helps to have a better internal design.
\section{Tools and Test Types}
Angular comes with tools to automate testing:
\begin{description}
\item[Jasmine]\footnote{\url{http://pivotal.github.io/jasmine/}} A behaviour-driven development framework for testing JavaScript code.
It provides a simple and self-descriptive syntax to write test suites.
\item[Angular Mocks] there are stub objects ready to load in tests (e.g. \texttt{\$httpBackend} mocks \ac{HTTP} calls)
\item[Karma]\footnote{\url{http://karma-runner.github.io/}} is a test runner to automate the execution of the test suites.
\end{description}
\ac{TDD} is explained in \fref{sec:testdrivendev}.
\ac{E2E} simulate user interaction by writing scenario tests.
They describe the expected behaviour of the application given a state and an interaction.
Each test has commands (e.g. "click on button with $id = 3$") and expectations (e.g. "the background colour is now shiny red").
Unit tests are created before the code itself is written (i.e. they first specify the behaviour of the software and then test the implementation).
Each test focuses on an individual and small part of the code: given an initial situation, the unit testing framework runs the operation being tested and finally asserts the result.
This project only uses unit testing to define the specification of the software and to test directives, services and controllers.
It is not possible to conduct \ac{E2E} testing because the \ac{UI} is built in run-time.
this testing strategy fits well with normal \ac{CRUD} applications, when developers know about the use cases of the software.
The software of this thesis only deals with rendering content applications, which can be of any nature.
If this thesis had focuses on reengineering one of the content applications, \ac{E2E} would have been a useful tool.
\section{Tests Definition}
Tests are written with Jasmine and are grouped in test suites.
These are \texttt{describe} blocks that contain tests in \texttt{it} blocks.
\lstinputlisting[label=test-example-generic,language=javascript, caption={Structure of a test suite}]{src/test-example-generic.js}
Listing \ref{test-example-generic} shows the structure of a test suite:
it can perform logic before and after each test (e.g. instantiate an object or flush \$http requests to guarantee that all tests start with the same system state and that do no test depends on another one).
All tests have the same pattern:
\begin{enumerate}
\item Set the initial situation (e.g. create an \ac{HTML} node)
\item Run an operation (e.g. compile the node)
\item Assert the results (e.g. expect a property in scope to have been set, or a counter to have been increased)
\end{enumerate}
\lstinputlisting[label=test-example-width,language=javascript, caption={Structure of a test suite}]{src/test-example-generic.js}
Listing \ref{test-example-width} demonstrates a real test.
The \texttt{width} directive test suite (called simply "width") belongs to a test suite called "UI directive".
It contains several\texttt{it} blocks that check one and only one result (e.g. the test for getting the value is called "should set the property to 40 for Catalan and 42 for French").
When karma runner executes all test suites, it creates a report with sentences like "UI directive: width directive should set the property to 42 for the default language".
The initial situation is an \ac{XML} node, the operation run is \$compile() and the asserts are the \texttt{expect()} operations.
\textbf{Dependency injection} Even though the internal design of the application minimises the coupling of components and tries to maximise cohesion, there are dependencies between some classes.
This is critical when it involves remote requests or using operations that are defined in another user class (as opposed to using well-tested code in the Angular core).
It is then desirable to use (and re-use) mocks in tests.
Dependency injection allows tests to mock dependencies: it loads a module with a mocked dependency of the same name that simply returns hard-coded values but offers the same interface.
No modifications in the real component are needed.
\lstinputlisting[label=test-di,language=javascript, caption={Dependency injection in tests}]{src/test-di.js}
Listing \ref{test-di} shows the implementation: modules are loaded to make them available to the test suite.
In the \texttt{beforeEach} clause it stores a reference to the injected element to a local variable.
Whenever a test calls an operation of the injected service, it will use the mock.
\begin{lstlisting}[label=test-mocks,language=javascript, caption=Mocks]
var m = angular.module('reemi.mocks.palProperties', []);
m.service('palProperties', function () {
this.toCSS = function (params) {
return "color:red;";
}
});
\end{lstlisting}
Mocks are components declared with the same name but in a different module (\ref{test-mocks}).
They are excluded from deployment to the robot.
\Fref{chap:app-unittests} contains a list of most of the relevant tests.
\section{Test Automation}
\emph{Fail early, fail often}: karma runner is a process watching the project.
It runs all tests on every change without disturbing the development and in less than two seconds.
Karma is a \textit{spectacular test runner for JavaScript} that can run tests in real browsers like Chrome or a program with QtWebKit and that can be integrated with WebStorm or launched from the console (listing \ref{test-launch-karma})
\begin{lstlisting}[label=test-launch-karma,language=bash, caption=Launching Karma Runner]
$ ./scripts/test.sh
INFO [karma]: Karma server started at http://localhost:9876/
INFO [launcher]: Starting browser Chrome
INFO [Chrome 28.0 (Linux)]: Connected on socket
id DxbVJNX0jIoe1CbaWf9V
Chrome 28.0 (Linux): Executed 143 of 143 SUCCESS
(0.843 secs / 0.432 secs)
\end{lstlisting}
It can be installed with \ac{npm} and configured with a file.
The configuration for this thesis includes jQuery, mocks and configures the browser to suit the needs of the environment.
In the first phase of the project, it used a browser based on QtWebKit instead of Chrome (\ref{test-qtwebkit}).
\begin{lstlisting}[label=test-qtwebkit,language=javascript, caption=Configuration to use QtWebkit browser]
browsers: ['/opt/Qt5.0.2/5.0.2/gcc/
examples/webkitwidgets/browser/browser']
\end{lstlisting}
The goal is to automate the testing in an environment as close to the real one as possible.
With this automation, refactoring is easier and more robust, and regressions are avoided.