-
Notifications
You must be signed in to change notification settings - Fork 45
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),@Autowiredor@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),@Autowiredor@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@Componentitself 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
@Nullablenor with@Autowired(required=false) - in class under test
FieldType fieldNameis 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
Labels
Type
Projects
Status