Skip to content

Commit 517984b

Browse files
authored
Merge pull request #50 from diffblue/afry/tg-24054-WriteTestsToAnnotation
add @WriteTestsTo annotation
2 parents afaf2a5 + d286d09 commit 517984b

File tree

4 files changed

+205
-54
lines changed

4 files changed

+205
-54
lines changed

README.md

Lines changed: 106 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -12,71 +12,79 @@ In turn this can be used by [Diffblue Cover](https://diffblue.com/cover) to tune
1212

1313
## Installation
1414

15-
Cover Annotations is published in the [Maven central repository](https://central.sonatype.com/artifact/com.diffblue.cover/cover-annotations/overview).
16-
In order to use the annotations simply add `cover-annotations` as a dependency to your project, for example copying the snippet for Maven or Gradle from the repository page.
15+
Cover Annotations is published in
16+
the [Maven central repository](https://central.sonatype.com/artifact/com.diffblue.cover/cover-annotations/overview).
17+
In order to use the annotations simply add `cover-annotations` as a dependency to your project, for example copying the
18+
snippet for Maven or Gradle from the repository page.
1719

1820
### Maven
1921

20-
For installation into a Maven project the `provided` scope is recommended so that the annotations are available at compile and test time, but are not bundled with the project output:
22+
For installation into a Maven project the `provided` scope is recommended so that the annotations are available at
23+
compile and test time, but are not bundled with the project output:
2124

2225
```
2326
<dependencies>
2427
<dependency>
2528
<groupId>com.diffblue.cover</groupId>
2629
<artifactId>cover-annotations</artifactId>
27-
<version>1.8.0</version>
30+
<version>1.9.0</version>
2831
<scope>provided</scope>
2932
</dependency>
3033
</dependencies>
3134
```
3235

3336
### Gradle
3437

35-
For installation into a Gradle project the `compileOnly` and `testImplementation` configurations are recommended so that the annotations are available at compile and test time, but are not bundled with the project output:
38+
For installation into a Gradle project the `compileOnly` and `testImplementation` configurations are recommended so that
39+
the annotations are available at compile and test time, but are not bundled with the project output:
3640

3741
```
3842
dependencies {
39-
compileOnly("com.diffblue.cover:cover-annotations:1.8.0")
43+
compileOnly("com.diffblue.cover:cover-annotations:1.9.0")
4044
41-
testImplementation("com.diffblue.cover:cover-annotations:1.8.0")
45+
testImplementation("com.diffblue.cover:cover-annotations:1.9.0")
4246
}
4347
```
4448

4549
## Usage
4650

4751
Annotations placed on packages affect tests for all classes and methods under test in that package.
48-
Annotations placed on classes affect tests for that class and all its methods under test, overriding package level annotations.
52+
Annotations placed on classes affect tests for that class and all its methods under test, overriding package level
53+
annotations.
4954
Annotations placed on methods affect just that method under test, overriding package and class level annotations.
5055

5156
The annotations will be respected by Diffblue Cover via both command line and IntelliJ Plugin.
52-
When used from the command line in conjunction with equivalent options then the command line options take priority over the annotations found.
57+
When used from the command line in conjunction with equivalent options then the command line options take priority over
58+
the annotations found.
5359

5460
### Mocking Annotations
5561

5662
Mocking annotations allow fine grained control over what mocking should be preferred when testing.
5763

5864
#### Using `@InTestsMock`
5965

60-
Perhaps you have a method that Diffblue Cover would ordinarily test using an `Integer` but you'd prefer to see it tested using `Mockito.mock(..)`.
66+
Perhaps you have a method that Diffblue Cover would ordinarily test using an `Integer` but you'd prefer to see it tested
67+
using `Mockito.mock(..)`.
6168
In this case you could annotate the method (or class, or package) to recommend mocking `Number`:
6269

6370
```java
6471
public class ClassUnderTest {
65-
@InTestsMock(Number.class)
66-
public static String methodUnderTest(Number number) {
67-
return String.valueOf(number.intValue());
68-
}
72+
@InTestsMock(Number.class)
73+
public static String methodUnderTest(Number number) {
74+
return String.valueOf(number.intValue());
75+
}
6976
}
7077
```
7178

72-
Conversely, if Diffblue Cover normally does mock a particular class, and you have a particular location where it shouldn't be then you can forbid it:
79+
Conversely, if Diffblue Cover normally does mock a particular class, and you have a particular location where it
80+
shouldn't be then you can forbid it:
7381

7482
```java
75-
public class ClassUnderTest {
76-
@InTestsMock(value = Number.class, decision = MockDecision.FORBIDDEN)
77-
public static String methodUnderTest(Number number) {
78-
return String.valueOf(number.intValue());
79-
}
83+
public class ClassUnderTest {
84+
@InTestsMock(value = Number.class, decision = MockDecision.FORBIDDEN)
85+
public static String methodUnderTest(Number number) {
86+
return String.valueOf(number.intValue());
87+
}
8088
}
8189
```
8290

@@ -89,36 +97,39 @@ public class ClassUnderTest {
8997
9098
#### Using `@InTestsMockConstruction`
9199
92-
Perhaps you have a method that Diffblue Cover is unable to test, and you think it could make more progress using `Mockito.mockConstruction(Random.class)`.
100+
Perhaps you have a method that Diffblue Cover is unable to test, and you think it could make more progress using
101+
`Mockito.mockConstruction(Random.class)`.
93102
In this case you could annotate the method (or class, or package) to recommend mocking construction of `Random`:
94103
95104
```java
96105
public class ClassUnderTest {
97-
@InTestsMockConstruction(Random.class)
98-
public static int methodUnderTest() {
99-
return new Random().nextInt();
100-
}
106+
@InTestsMockConstruction(Random.class)
107+
public static int methodUnderTest() {
108+
return new Random().nextInt();
109+
}
101110
}
102111
```
103112
104113
> [!NOTE]
105-
> Note that using `@InTestsMockConstruction` has the same effect as, and can be overridden by, Cover CLI command line option:
114+
> Note that using `@InTestsMockConstruction` has the same effect as, and can be overridden by, Cover CLI command line
115+
> option:
106116
>
107117
> ```
108118
> dcover create --mock-construction ClassToMockConstruction
109119
> ```
110120
111121
#### Using `@InTestsMockStatic`
112122
113-
Perhaps you have a method that Diffblue Cover is unable to test, and you think it could make more progress using `Mockito.mockStatic(UUID.class)`.
123+
Perhaps you have a method that Diffblue Cover is unable to test, and you think it could make more progress using
124+
`Mockito.mockStatic(UUID.class)`.
114125
In this case you could annotate the method (or class, or package) to recommend mocking static methods of `UUID`:
115126
116127
```java
117128
public class ClassUnderTest {
118-
@InTestsMockStatic(UUID.class)
119-
public static Path methodUnderTest() {
120-
return Paths.get(UUID.randomUUID() + ".zip");
121-
}
129+
@InTestsMockStatic(UUID.class)
130+
public static Path methodUnderTest() {
131+
return Paths.get(UUID.randomUUID() + ".zip");
132+
}
122133
}
123134
```
124135
@@ -136,7 +147,8 @@ Custom input annotations allow particular inputs to be recommended to Diffblue C
136147
#### Using `@InTestsUseEnums`
137148
138149
The `@InTestsUseEnums` annotation allows the user to recommend specific `enum` literal values to use in tests.
139-
Sometimes this can be useful to control the values used for cosmetic reasons, but it can also be useful when Cover is unable to identify values to cover all cases.
150+
Sometimes this can be useful to control the values used for cosmetic reasons, but it can also be useful when Cover is
151+
unable to identify values to cover all cases.
140152
141153
```java
142154
public static boolean isDateOrTimeBased(@InTestsUseEnums({"SECONDS", "YEARS", "FOREVER"}) ChronoUnit chronoUnit) {
@@ -147,7 +159,8 @@ public static boolean isDateOrTimeBased(@InTestsUseEnums({"SECONDS", "YEARS", "F
147159
#### Using `@InTestsUseClasses`
148160

149161
The `@InTestsUseClasses` annotation allows the user to recommend specific `Class` literal values to use in tests.
150-
Sometimes this can be useful to control the values used for cosmetic reasons, but it can also be useful when Cover is unable to identify values to cover all cases.
162+
Sometimes this can be useful to control the values used for cosmetic reasons, but it can also be useful when Cover is
163+
unable to identify values to cover all cases.
151164
For example the following method is annotated with an example class literal to achieve a positive test:
152165

153166
```java
@@ -159,8 +172,10 @@ public static boolean isAnnotation(@InTestsUseClasses(Nullable.class) Class<?> t
159172
#### Using `@InTestsUseStrings`
160173

161174
The `@InTestsUseStrings` annotation allows the user to recommend specific `String` values to use in tests.
162-
Sometimes this can be useful to control the values used for cosmetic reasons, but it can also be useful when Cover is unable to identify values to cover all cases.
163-
For example the following method is annotated with some genuine examples of song titles that can be used to achieve coverage:
175+
Sometimes this can be useful to control the values used for cosmetic reasons, but it can also be useful when Cover is
176+
unable to identify values to cover all cases.
177+
For example the following method is annotated with some genuine examples of song titles that can be used to achieve
178+
coverage:
164179

165180
```java
166181
public static boolean isDayRelatedSongTitle(@InTestsUseStrings({"I Don't Like Mondays", "Here Comes The Weekend"}) String title) {
@@ -174,10 +189,13 @@ public static boolean isDayRelatedSongTitle(@InTestsUseStrings({"I Don't Like Mo
174189
#### Using `@InTestsUseCharacters`
175190

176191
The `@InTestsUseCharacters` annotation allows the user to recommend specific `char` values to use in tests.
177-
Sometimes this can be useful to control the values used for cosmetic reasons, but it can also be useful when Cover is unable to identify values to cover all cases.
178-
For example the following method is annotated with a genuine examples characters that make up a Unicode surrogate pair that can be used to achieve a positive test:
192+
Sometimes this can be useful to control the values used for cosmetic reasons, but it can also be useful when Cover is
193+
unable to identify values to cover all cases.
194+
For example the following method is annotated with a genuine examples characters that make up a Unicode surrogate pair
195+
that can be used to achieve a positive test:
179196

180197
```java
198+
181199
@Nullable
182200
public static Integer toNullableCodePoint(
183201
@InTestsUseCharacters('\uD801') char high,
@@ -192,31 +210,34 @@ public static Integer toNullableCodePoint(
192210
#### Using `@InTestsUseBytes`
193211

194212
The `@InTestsUseBytes` annotation allows the user to recommend specific `byte` values to use in tests.
195-
Sometimes this can be useful to control the values used for cosmetic reasons, but it can also be useful when Cover is unable to identify values to cover all cases.
213+
Sometimes this can be useful to control the values used for cosmetic reasons, but it can also be useful when Cover is
214+
unable to identify values to cover all cases.
196215
For example the following method is annotated to use a specific preferred value:
197216

198217
```java
199-
public static String toUpperHexString(@InTestsUseBytes((byte)0xD1) byte input) {
218+
public static String toUpperHexString(@InTestsUseBytes((byte) 0xD1) byte input) {
200219
return Long.toHexString(input).toUpperCase();
201220
}
202221
```
203222

204223
#### Using `@InTestsUseShorts`
205224

206225
The `@InTestsUseShorts` annotation allows the user to recommend specific `short` values to use in tests.
207-
Sometimes this can be useful to control the values used for cosmetic reasons, but it can also be useful when Cover is unable to identify values to cover all cases.
226+
Sometimes this can be useful to control the values used for cosmetic reasons, but it can also be useful when Cover is
227+
unable to identify values to cover all cases.
208228
For example the following method is annotated to use a specific preferred value:
209229

210230
```java
211-
public static String toUpperHexString(@InTestsUseShorts((short)0xD1FF) short input) {
231+
public static String toUpperHexString(@InTestsUseShorts((short) 0xD1FF) short input) {
212232
return Long.toHexString(input).toUpperCase();
213233
}
214234
```
215235

216236
#### Using `@InTestsUseIntegers`
217237

218238
The `@InTestsUseIntegers` annotation allows the user to recommend specific `int` values to use in tests.
219-
Sometimes this can be useful to control the values used for cosmetic reasons, but it can also be useful when Cover is unable to identify values to cover all cases.
239+
Sometimes this can be useful to control the values used for cosmetic reasons, but it can also be useful when Cover is
240+
unable to identify values to cover all cases.
220241
For example the following method is annotated to use a specific preferred value:
221242

222243
```java
@@ -228,7 +249,8 @@ public static String toUpperHexString(@InTestsUseIntegers(0xD1FFB) int input) {
228249
#### Using `@InTestsUseLongs`
229250

230251
The `@InTestsUseLongs` annotation allows the user to recommend specific `long` values to use in tests.
231-
Sometimes this can be useful to control the values used for cosmetic reasons, but it can also be useful when Cover is unable to identify values to cover all cases.
252+
Sometimes this can be useful to control the values used for cosmetic reasons, but it can also be useful when Cover is
253+
unable to identify values to cover all cases.
232254
For example the following method is annotated to use a specific preferred value:
233255

234256
```java
@@ -240,7 +262,8 @@ public static String toUpperHexString(@InTestsUseLongs(0xD1FFBL) long input) {
240262
#### Using `@InTestsUseFloats`
241263

242264
The `@InTestsUseFloats` annotation allows the user to recommend specific `float` values to use in tests.
243-
Sometimes this can be useful to control the values used for cosmetic reasons, but it can also be useful when Cover is unable to identify values to cover all cases.
265+
Sometimes this can be useful to control the values used for cosmetic reasons, but it can also be useful when Cover is
266+
unable to identify values to cover all cases.
244267
For example the following method is annotated to use a specific preferred value:
245268

246269
```java
@@ -252,7 +275,8 @@ public static boolean isNearPi(@InTestsUseFloats(3.14159f) float input) {
252275
#### Using `@InTestsUseDoubles`
253276

254277
The `@InTestsUseDoubles` annotation allows the user to recommend specific `double` values to use in tests.
255-
Sometimes this can be useful to control the values used for cosmetic reasons, but it can also be useful when Cover is unable to identify values to cover all cases.
278+
Sometimes this can be useful to control the values used for cosmetic reasons, but it can also be useful when Cover is
279+
unable to identify values to cover all cases.
256280
For example the following method is annotated to use a specific preferred value:
257281

258282
```java
@@ -263,22 +287,25 @@ public static boolean isNearPi(@InTestsUseDoubles(Math.PI) float input) {
263287

264288
### Interesting Value Annotations
265289

266-
Interesting value annotations allow users to promote existing fields and methods to be identified and used in particular roles by Diffblue Cover when writing tests.
290+
Interesting value annotations allow users to promote existing fields and methods to be identified and used in particular
291+
roles by Diffblue Cover when writing tests.
267292

268293
#### Using `@InterestingTestFactory`
269294

270295
Indicates the annotated method as a useful factory method for use in tests.
271-
Cover will automatically recognise factory methods that simply return a newly created instance, but may not identify more complicated factories.
296+
Cover will automatically recognise factory methods that simply return a newly created instance, but may not identify
297+
more complicated factories.
272298
This annotation allows such factory methods to be manually annotated so that Cover considers them for producing inputs.
273-
For example the following method under test takes a `User` as input, but the `User` constructor is private and Cover doesn't naturally consider `ofStaff(String)` to be a safe factory method to call.
274-
By annotating the `ofStaff(String)` with `@InterstingTestFactory` we can tell Cover that this should be considered a good factory method to use in tests.
299+
For example the following method under test takes a `User` as input, but the `User` constructor is private and Cover
300+
doesn't naturally consider `ofStaff(String)` to be a safe factory method to call.
301+
By annotating the `ofStaff(String)` with `@InterstingTestFactory` we can tell Cover that this should be considered a
302+
good factory method to use in tests.
275303

276304
```java
277305
public String getUserDisplayString(User user) {
278306
if (user.manager) {
279307
return user.username + " (manager)";
280-
}
281-
else {
308+
} else {
282309
return user.username;
283310
}
284311
}
@@ -326,7 +353,7 @@ public class CarFactory {
326353
public static Car getFirstCar() {
327354
return INSTANCE.cars.get(0);
328355
}
329-
356+
330357
// and so on...
331358
}
332359
```
@@ -343,6 +370,33 @@ public class CarPainter {
343370
}
344371
```
345372

373+
### Test Organization Annotations
374+
375+
Test organization annotations allow users to control how tests are organized and structured.
376+
377+
#### Using `@WriteTestsTo`
378+
379+
The `@WriteTestsTo` annotation directs Diffblue Cover to write tests for a specific source class into a designated test
380+
class file, rather than following the default naming template (configured via `--class-name-template`).
381+
382+
The specified test class name must be alphanumeric, and the test class will be created in the test folder under the same
383+
package structure as the source class.
384+
385+
```java
386+
package com.example.myapp;
387+
388+
@WriteTestsTo("CustomTestClassName")
389+
public class SourceClass {
390+
public String getValue() {
391+
return "example";
392+
}
393+
}
394+
// Tests will be written to: src/test/java/com/example/myapp/CustomTestClassName.java
395+
```
396+
397+
> [!NOTE]
398+
> This annotation can only be applied at the class level.
399+
346400
### Experimental Annotations
347401

348402
Experimental annotations should not be used in a production setting, but are

pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<!--
3-
~ Copyright 2024 Diffblue Limited.
3+
~ Copyright 2024 - 2026 Diffblue Limited.
44
~ Licensed under the Apache License, Version 2.0 (the "License").
55
~ You may not use this file except in compliance with the License.
66
~ A copy of the License is located at
@@ -16,7 +16,7 @@
1616
<modelVersion>4.0.0</modelVersion>
1717
<groupId>com.diffblue.cover</groupId>
1818
<artifactId>cover-annotations</artifactId>
19-
<version>1.8.0</version>
19+
<version>1.9.0</version>
2020
<packaging>jar</packaging>
2121

2222
<name>Cover Annotations</name>

0 commit comments

Comments
 (0)