Skip to content

Commit 980053b

Browse files
committed
copyedit gui->testing
1 parent 3d91c80 commit 980053b

13 files changed

+580
-432
lines changed

doc/Glossary.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ A method of changing the internal parameters of an emulator to mimic the behavio
3232

3333
Slits used on each of the Muon instruments to control the neutron flux to the sample. Each "jaw" pivots on one edge, much like a door on a hinge.
3434

35+
## BDD
36+
37+
Behaviour-driven development. See the [Agile Alliance definition of BDD](https://www.agilealliance.org/glossary/bdd/),
38+
and [how we use BDD for testing in Squish](/client/testing/System-Testing-with-Squish-BDD).
39+
3540
## Block
3641

3742
## Block Archive

doc/client/testing/Adding-Unit-Tests.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Adding tests
22

3-
For more detailed information see [an_introduction_to_unit_testing.rst](An-Introduction-to-Unit-Testing).
3+
:::{seealso}
4+
- [Introduction to unit testing](An-Introduction-to-Unit-Testing)
5+
:::
46

57
It is relatively simple to add unit tests for a plug-in in such a way that maven can run them as part of the build.
68

@@ -9,7 +11,8 @@ Here are the steps required in Eclipse:
911
* Create a new Fragment Project
1012
* File > New > Project... > Plug-in Development > Fragment Project
1113
* Set the project name to `\<the full name of the plug-in to test\>.tests`
12-
* Change the location to the repository rather than the workspace: `xxx\ibex_gui\base\\\<project_name>` (don't forget the project name!!)
14+
* Change the location to the repository rather than the workspace: `xxx\ibex_gui\base\\\<project_name>` (don't
15+
forget the project name!!)
1316
* Click "Next"
1417
* Make sure the Execution Environment points at the correct version of Java (currently JavaSE-11)
1518
* Click the "Browse" button next to "Plug-in ID"
@@ -27,7 +30,8 @@ Here are the steps required in Eclipse:
2730
* The class name **must** end in Test to be picked up by the automated build
2831

2932
* Add tests to the class
30-
* Add `org.junit` and `org.mockito` (if required) to the 'Required Plug-ins', under the Dependencies tab for the manifest
33+
* Add `org.junit` and `org.mockito` (if required) to the 'Required Plug-ins', under the Dependencies tab for the
34+
manifest
3135

3236
* Add the test plug-in to the Maven build by [following these steps](../coding/Adding-a-Plugin-or-Feature-to-Maven-Build)
3337

Lines changed: 98 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -1,93 +1,98 @@
11
# An introduction to unit testing
22

3-
To create unit tests for an Eclipse plug-in a Fragment Project is used. When creating a Fragment Project we assign the plug-in we wish to test as a Host Plug-in.
3+
To create unit tests for an Eclipse plug-in, a Fragment Project is used.
4+
When creating a Fragment Project, we assign the plug-in we wish to test as a Host Plug-in.
45
Eclipse automatically gives the Fragment access to the classes in the original plug-in.
5-
In the Fragment Project we create classes to test the classes in the original plug-in.
6+
In the Fragment Project we implement test classes to test the original plug-in's implementation.
67

78
## A simple example
89

9-
Open the wizard for creating a standard plug-in in Eclipse (File->New->Plug-in Project) and complete the following steps (if values not specified then use the defaults):
10+
Open the wizard for creating a standard plug-in in Eclipse (File->New->Plug-in Project) and complete the following
11+
steps (if values not specified then use the defaults):
1012

11-
* Set "Project name" to org.myexample.plugin
13+
* Set "Project name" to `org.myexample.plugin`
1214
* Click "Next"
1315
* Uncheck "Generate an activator, a Java class that controls the plug-in's life cycle"
1416
* Uncheck "This plug-in will make contributions to the UI"
1517
* Put "No" for "Would you like to create a rich client application?"
1618
* Click "Finish"
1719

18-
The will create the plug-in. Inside the src folder create a package called org.myexample.plugin.classes and add a class called StringManipulator.
19-
Add the following code to the class:
20+
This will create the plug-in. Inside the src folder create a package called `org.myexample.plugin.classes` and add a
21+
class called StringManipulator. Add the following code to the class:
2022

21-
```
22-
package org.myexample.plugin.classes;
23-
public class StringManipulator {
24-
25-
public String addStrings(String one, String two) {
26-
return one;
27-
}
23+
```java
24+
package org.myexample.plugin.classes;
25+
public class StringManipulator {
26+
27+
public String addStrings(String one, String two) {
28+
return one;
2829
}
30+
}
2931
```
3032

31-
Now to create the Fragment Project. Open the Fragment Project wizard under File->New->Other->Plug-in Development->Fragment Project and complete the following steps:
33+
Now create the Fragment Project. Open the Fragment Project wizard under
34+
File->New->Other->Plug-in Development->Fragment Project, and complete the following steps:
3235

33-
* Set "Project name" to org.myexample.plugin.tests (i.e the original plug-in name plus ".tests" - this is our naming convention)
36+
* Set "Project name" to `org.myexample.plugin.tests` (i.e. the original plug-in name plus `.tests` - this is our naming
37+
convention)
3438
* Click "Next"
3539
* Under "Host Plug-in" click the "Browse" button and select the original plug-in
3640
* Click "Finish"
3741

38-
Eclipse will now create the Fragment Project. We need to manually add the JUnit plug-in as a dependency for the Fragment Project, to do this:
42+
Eclipse will now create the Fragment Project. We need to manually add the JUnit plug-in as a dependency for the
43+
Fragment Project, to do this:
3944

40-
* Open the MANIFEST.MF file
45+
* Open the `MANIFEST.MF` file
4146
* Select the "Dependencies" tab
4247
* Under "Required Plug-ins" click the "Add" button
43-
* In the dialog, type org.junit and select the plug-in listed (it should be version 4+)
48+
* In the dialog, type `org.junit` and select the plug-in listed (it should be version 4+)
4449
* Click "OK"
4550
* Save the changes
4651

47-
In the src directory of the Fragment Project create a package called "org.myexample.plugin.tests".
48-
Add a class called "StringManipulatorTest" - the name **MUST** end in Test for the build system to recognise it.
52+
In the src directory of the Fragment Project create a package called `org.myexample.plugin.tests`.
53+
Add a class called `StringManipulatorTest` - the name **MUST** end in Test for the build system to recognise it.
54+
55+
Now create a test, add the following code to the `StringManipulatorTest` class:
4956

50-
Okay let's create a test, add the following code to the StringManipulatorTest class:
57+
```java
58+
package org.myexample.plugin.tests;
5159

52-
```
53-
package org.myexample.plugin.tests;
60+
import static org.junit.Assert.*;
5461

55-
import static org.junit.Assert.*;
62+
import org.junit.Test;
63+
import org.myexample.plugin.classes.StringManipulator;
5664

57-
import org.junit.Test;
58-
import org.myexample.plugin.classes.StringManipulator;
59-
60-
public class StringManipulatorTest {
61-
@Test
62-
public void add_hello_to_world() {
63-
// Arrange
64-
StringManipulator strMan = new StringManipulator();
65+
public class StringManipulatorTest {
66+
@Test
67+
public void add_hello_to_world() {
68+
// Arrange
69+
StringManipulator strMan = new StringManipulator();
6570

66-
// Act
67-
String ans = strMan.addStrings("Hello", "World");
71+
// Act
72+
String ans = strMan.addStrings("Hello", "World");
6873

69-
// Assert
70-
assertEquals("HelloWorld", ans);
74+
// Assert
75+
assertEquals("HelloWorld", ans);
7176

72-
}
7377
}
78+
}
7479
```
7580

7681
To run the test right-click on the Fragment Project and select Run As->JUnit Test. The test should run and fail like so:
7782

7883
![Failed test](failed_test.png)
7984

80-
Clearly there is something wrong with the original code in addStrings, so let's fix that by changing:
85+
The test failed, so there is something wrong with the original code in `addStrings`; fix that by changing:
8186

82-
```
87+
```java
8388
public String addStrings(String one, String two) {
8489
return one;
8590
}
8691
```
8792

8893
to:
8994

90-
```
95+
```java
9196
public String addStrings(String one, String two) {
9297
return one + two;
9398
}
@@ -100,23 +105,19 @@ Now the test should pass if it is run again:
100105
JUnit has many useful features, here are a select few.
101106

102107
* other asserts such as `assertTrue`, `assertArrayEquals`, `assertNotEqual` and `assertNotNull`
103-
104108
* assert that an error is thrown:
105-
106-
```
109+
```java
107110
@Test(expected=IndexOutOfBoundsException.class)
108111
public void raises_IndexOutOfBoundsException() {
109112
ArrayList emptyList = new ArrayList();
110113
Object o = emptyList.get(0);
111114
}
112115
```
113-
114116
* set-up and teardown methods - these are code snippets that are run before and after **each** test:
115-
116-
```
117+
```java
117118
private List<String> names;
118-
119-
@Before
119+
120+
@Before
120121
public void setUp() {
121122
// Called before each test
122123
names = new ArrayList<String>();
@@ -131,25 +132,27 @@ JUnit has many useful features, here are a select few.
131132
names.clear();
132133
}
133134

134-
@Test
135-
public void concatenate_names() {
136-
// Arrange
137-
StringManipulator strMan = new StringManipulator();
135+
@Test
136+
public void concatenate_names() {
137+
// Arrange
138+
StringManipulator strMan = new StringManipulator();
138139

139-
// Act
140-
String ans = strMan.concatenateNames(names);
140+
// Act
141+
String ans = strMan.concatenateNames(names);
141142

142-
// Assert
143-
assertEquals("Tom, Dick and Harry", ans);
143+
// Assert
144+
assertEquals("Tom, Dick and Harry", ans);
144145

145-
}
146+
}
146147
```
147-
148-
Note: Each test should be independent of the other tests as there is no guarantee of the order they are run in.
149148

150-
* BeforeClass and AfterClass - these are run once before the first test and after the last test in a class respectively:
149+
:::{note}
150+
Each test should be independent of other tests; there is no guarantee of the order they are run in.
151+
:::
151152

152-
```
153+
* `BeforeClass` and `AfterClass` - these are run once before the first test and after the last test in a class
154+
respectively:
155+
```java
153156
@BeforeClass
154157
public static void oneTimeSetUp() {
155158
// Perhaps create a dummy file or something shared by more than one test
@@ -167,69 +170,49 @@ See [test naming](Test-naming).
167170

168171
## Mockito
169172

170-
Mockito is a framework for creating mock objects that can be substituted for real objects to make testing easier and more specific.
171-
For example: writing tests that don't rely on a database, file or network connection being present.
173+
Mockito is a framework for creating mock objects that can be substituted for real objects to make testing easier and
174+
more specific. For example: writing tests that don't rely on a database, file or network connection being present.
172175

173-
Like JUnit is can be used inside a Fragment Project after the dependency is added (`org.mockito`).
174-
175-
An example of using Mockito would be to mock a database wrapper so that a real database is not required:
176+
Like JUnit, it can be used inside a Fragment Project after the dependency is added (`org.mockito`).
176177

177-
```
178-
@Test
179-
public void get_row_data() {
180-
// Arrange
181-
// Create a mock database wrapper as we are not testing that
182-
DatabaseWrapper wrapper = mock(DatabaseWrapper.class);
183-
184-
// Create a mock "response"
185-
List<String> data = new ArrayList<String>();
186-
data.add("John");
187-
data.add("Smith");
188-
data.add("01/01/1955");
189-
when(wrapper.getRowData(0)).thenReturn(data); // This is the key line
190-
191-
// This is the object we are really testing
192-
DataHolder dataHolder = new DataHolder(wrapper);
193-
194-
// Act
195-
List<String> ans = dataHolder.getFirstRow();
196-
197-
// Assert
198-
assertEquals(data, ans);
199-
}
200-
```
201-
202-
For more detail on Mockito see [here](Using-Mockito-for-Testing-in-the-GUI).
178+
:::{seealso}
179+
For more detail & examples on Mockito see [here](Mockito), and the upstream documentation
180+
[here](https://javadoc.io/doc/org.mockito/mockito-core/latest/org.mockito/org/mockito/Mockito.html).
181+
:::
203182

204183
## Code coverage
205184

206185
It is useful to see what parts of a plug-in's code are used or not used by the unit tests.
207-
If a piece of code is not used by the unit tests then that may mean that an extra test is required
208-
209-
Unit test code coverage can be examined inside Eclipse using EclEmma which can be installed via the Eclipse Marketplace (under the "Help" menu).
210-
Once EclEmma is installed the coverage of the unit tests can be examined. Right-click on the test project and select Coverage As->JUnit Test. This will run the tests and calculate the coverage, the results should look something like this:
186+
If a piece of code is not used by the unit tests, then that may mean that an extra test is required.
211187

188+
To examine code coverage, right-click on the test project and select Coverage As->JUnit Test.
189+
This will run the tests and calculate the coverage, the results should look something like this:
212190

213191
![Coverage result](coverage_result.png)
214192

215193
From the results it can be seen that 63.2% of the StringManipulator code is used by the unit tests.
216-
The code that isn't used is highlighted in red - for this example we can see that we need to write a test that tests the reverseString method.
194+
The code that isn't used is highlighted in red - for this example we can see that we need to write a test that tests
195+
the `reverseString` method.
217196

197+
:::{tip}
198+
Code coverage is provided by the `EclEmma` add-on, which is installed by default in the Eclipse for RCP developers
199+
build of the IDE. If it is not already installed, it can be installed from the Eclipse marketplace.
200+
:::
218201

219202
## Troubleshooting
220203

221-
### ClassNotFoundException
204+
### `ClassNotFoundException`
222205

223206
Running the tests in Eclipse might crash with an error like:
224207

225208
```
226-
Class not found org.myexample.plugin.tests.StringManipulatorTest
227-
java.lang.ClassNotFoundException: org.myexample.plugin.tests.StringManipulatorTest
228-
at java.net.URLClassLoader.findClass(Unknown Source)
229-
at java.lang.ClassLoader.loadClass(Unknown Source)
230-
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
231-
at java.lang.ClassLoader.loadClass(Unknown Source)
232-
...
209+
Class not found org.myexample.plugin.tests.StringManipulatorTest
210+
java.lang.ClassNotFoundException: org.myexample.plugin.tests.StringManipulatorTest
211+
at java.net.URLClassLoader.findClass(Unknown Source)
212+
at java.lang.ClassLoader.loadClass(Unknown Source)
213+
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
214+
at java.lang.ClassLoader.loadClass(Unknown Source)
215+
...
233216
```
234217

235218
This is a known bug and there is a workaround:
@@ -240,16 +223,20 @@ This is a known bug and there is a workaround:
240223
* Select "Add Folders" and click "OK"
241224
* In the new dialog, expand the test plug-in and select the "bin" folder and click "OK"
242225
* On the original dialog, click "Apply" and then "Run"
243-
* Hopefully, the tests will now work and you should be able to re-run them in the normal way
226+
* The tests should now work, and you should be able to re-run them in the normal way
244227

245228
### Eclipse is not picking up new tests
246229

247-
If Eclipse is not picking up changes when you add tests you may need to change the default output folder for tests for Maven to pick it up.
230+
If Eclipse is not picking up changes when you add tests, you may need to change the default output folder for tests for
231+
Maven to pick it up.
248232

249233
* Right-click on the tests plug-in, go to properties, Java build path
250-
* Change the output folder to target/test-classes (you may need to create this folder first by clicking browse, selecting target and adding the test-classes folder)
251-
* If this does not work try deleting the target/test-classes folder first, if it existed already, and do a clean rebuild of the workspace
234+
* Change the output folder to target/test-classes (you may need to create this folder first by clicking browse,
235+
selecting target and adding the test-classes folder)
236+
* If this does not work try deleting the target/test-classes folder first, if it existed already, and do a clean
237+
rebuild of the workspace
252238

253-
### IncompatibleClassChangeError
239+
### `IncompatibleClassChangeError`
254240

255-
If the tests are failing because of an IncompatibleClassChangeError error then the solution is to delete the bin and target folders for both the main plug-in and the corresponding test plug-in
241+
If the tests are failing because of an IncompatibleClassChangeError error then the solution is to delete the bin and
242+
target folders for both the main plug-in and the corresponding test plug-in.

0 commit comments

Comments
 (0)