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)
- 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
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);
...
}
}
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
NPEtest forequals()method, however there's no such test because fields ofOrderare erroneously speculated to be non-null.Expected behavior
At the moment it seems that we should consider
FieldType fieldNameto be non-null, iff one of the following statements holds (cursive is to be discussed):@Autowired(required=true),@Autowiredor@Inject@Autowired(required=true),@Autowiredor@Inject@Autowired(required=false), while the class itself is annotated with@Component-like annotation (either@Componentitself or other annotation that is itself annotated with@Component)FieldType(or its subtype)@Nullablenor with@Autowired(required=false)FieldType fieldNameis the only field whose type is a super type of said parameter typefieldNameIf some tests require mock to be assigned to a field of class under test, while other require
nullto be assigned, then@InjectMockand@Mockfields are generated as before, whilenullis assigned explicitly in the test method body, like this: