Description
Description
Ever since #2034 was "fixed", in "No configuration" mode of Spring unit tests it's always been speculated that fields of class under test can't be null
, which is not correct.
Consider the following class under test, there should be NPE
test for equals()
method, however there's no such test because fields of Order
are erroneously speculated to be non-null
.
@Getter
@Setter
@Builder
@ToString
@Jacksonized
@NoArgsConstructor
@AllArgsConstructor
@Entity
@EqualsAndHashCode
@Table(name = "orders")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
@Email
@NotEmpty
String buyer;
Double price;
int qty;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || !(o instanceof Order)) return false;
Order order = (Order) o;
return qty == order.qty && id.equals(order.id) && buyer.equals(order.buyer) && price.equals(order.price);
}
@Override
public int hashCode() {
return Objects.hash(id, buyer, price, qty);
}
}
Expected behavior
At the moment it seems that we should consider FieldType fieldName
to be non-null
, iff one of the following statements holds (cursive is to be discussed):
- the field itself is annotated with
@Autowired(required=true)
,@Autowired
or@Inject
- all of the following statements hold:
- one of the following statements hold:
- there’s a constructor or a method annotated with
@Autowired(required=true)
,@Autowired
or@Inject
- there’s only one constructor defined in the classs, said constructor is not annotated with
@Autowired(required=false)
, while the class itself is annotated with@Component
-like annotation (either@Component
itself or other annotation that is itself annotated with@Component
)
- there’s a constructor or a method annotated with
- said constructor/method accepts a parameter of type
FieldType
(or its subtype) - said parameter is not annotated with
@Nullable
nor with@Autowired(required=false)
- in class under test
FieldType fieldName
is the only field whose type is a super type of said parameter type - said constructor/method contains an assignment of said parameter to
fieldName
- said constructor/method only contain assignment and invocation instructions
- one of the following statements hold:
If some tests require mock to be assigned to a field of class under test, while other require null
to be assigned, then @InjectMock
and @Mock
fields are generated as before, while null
is assigned explicitly in the test method body, like this:
public class ServiceTest {
@InjectMock
public ServiceUnderTest serviceUnderTest;
@Mock
public ExternalDependency externalDependency;
@Test
public void testThatUsesMock() {
when(externalDependency.use(any())).thenReturn(null);
...
}
@Test
public void testThatUsesNull() {
serviceUnderTest.setExternalDependency(null);
...
}
}
Metadata
Metadata
Assignees
Type
Projects
Status