Open EgorkaKulikov opened 1 year ago
@IlyaMuravjov could you provide an example of the behaviour we would like to improve here? I tried to construct it manually and realised that I do not catch a point.
@EgorkaKulikov when I generate unit tests for OwnerController.findOwner()
method in spring-petclinic project with or without configuration I get the following test, that mocks Owner
constructor (and also for some reason creates expectedMock
variable that is never used in any asserts):
/**
* @utbot.classUnderTest {@link OwnerController}
* @utbot.methodUnderTest {@link OwnerController#findOwner(Integer)}
* @utbot.executesCondition {@code (ownerId == null): True}
* @utbot.returnsFrom {@code return ownerId == null ? new Owner() : this.owners.customFindById(ownerId);}
*/
@Test
@DisplayName("findOwner: ownerId == null : True -> return ownerId == null ? new Owner() : this.owners.customFindById(ownerId)")
public void testFindOwner_OwnerIdEqualsNull() throws ClassNotFoundException, IllegalAccessException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException {
MockedConstruction mockedConstruction = null;
try {
mockedConstruction = mockConstruction(Owner.class, (Owner ownerMock, Context context) -> {
});
Owner actual = ownerController.findOwner(null);
Owner expectedMock = mock(Owner.class);
setField(expectedMock, "org.springframework.samples.petclinic.owner.Owner", "address", null);
setField(expectedMock, "org.springframework.samples.petclinic.owner.Owner", "city", null);
setField(expectedMock, "org.springframework.samples.petclinic.owner.Owner", "telephone", null);
setField(expectedMock, "org.springframework.samples.petclinic.owner.Owner", "pets", null);
setField(expectedMock, "org.springframework.samples.petclinic.model.Person", "firstName", null);
setField(expectedMock, "org.springframework.samples.petclinic.model.Person", "lastName", null);
setField(expectedMock, "org.springframework.samples.petclinic.model.BaseEntity", "id", null);
String actualAddress = ((String) getFieldValue(actual, "org.springframework.samples.petclinic.owner.Owner", "address"));
assertNull(actualAddress);
String actualCity = ((String) getFieldValue(actual, "org.springframework.samples.petclinic.owner.Owner", "city"));
assertNull(actualCity);
String actualTelephone = ((String) getFieldValue(actual, "org.springframework.samples.petclinic.owner.Owner", "telephone"));
assertNull(actualTelephone);
List actualPets = actual.pets;
assertNull(actualPets);
String actualFirstName = ((String) getFieldValue(actual, "org.springframework.samples.petclinic.model.Person", "firstName"));
assertNull(actualFirstName);
String actualLastName = ((String) getFieldValue(actual, "org.springframework.samples.petclinic.model.Person", "lastName"));
assertNull(actualLastName);
Integer actualId = ((Integer) getFieldValue(actual, "org.springframework.samples.petclinic.model.BaseEntity", "id"));
assertNull(actualId);
} finally {
mockedConstruction.close();
}
}
I also get the same test when I disable Mock static methods
, but this time I also get the following warning.
/* WARNING!!! Automatically used "Mockito static mocking" framework for mocking statics
because execution encountered flaky methods
To change this behaviour edit [Settings -> UtBot -> Force static mocking] */
When I disable both Mock static methods
and Force static mocking
(they both were enabled by default) I finally able to get a test, that doesn't mock Owner
constructor, although it still renders a warning and creates unused expectedMock
.
/**
* @utbot.classUnderTest {@link OwnerController}
* @utbot.methodUnderTest {@link OwnerController#findOwner(Integer)}
* @utbot.executesCondition {@code (ownerId == null): True}
* @utbot.returnsFrom {@code return ownerId == null ? new Owner() : this.owners.customFindById(ownerId);}
*/
@Test
@DisplayName("findOwner: ownerId == null : True -> return ownerId == null ? new Owner() : this.owners.customFindById(ownerId)")
public void testFindOwner_OwnerIdEqualsNull() throws ClassNotFoundException, IllegalAccessException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException {
/* Warning!!! This test can be flaky because execution encountered flaky methods,
but no "static mocking" was selected */
Owner actual = ownerController.findOwner(null);
Owner expectedMock = mock(Owner.class);
setField(expectedMock, "org.springframework.samples.petclinic.owner.Owner", "address", null);
setField(expectedMock, "org.springframework.samples.petclinic.owner.Owner", "city", null);
setField(expectedMock, "org.springframework.samples.petclinic.owner.Owner", "telephone", null);
setField(expectedMock, "org.springframework.samples.petclinic.owner.Owner", "pets", null);
setField(expectedMock, "org.springframework.samples.petclinic.model.Person", "firstName", null);
setField(expectedMock, "org.springframework.samples.petclinic.model.Person", "lastName", null);
setField(expectedMock, "org.springframework.samples.petclinic.model.BaseEntity", "id", null);
String actualAddress = ((String) getFieldValue(actual, "org.springframework.samples.petclinic.owner.Owner", "address"));
assertNull(actualAddress);
String actualCity = ((String) getFieldValue(actual, "org.springframework.samples.petclinic.owner.Owner", "city"));
assertNull(actualCity);
String actualTelephone = ((String) getFieldValue(actual, "org.springframework.samples.petclinic.owner.Owner", "telephone"));
assertNull(actualTelephone);
List actualPets = actual.pets;
assertNull(actualPets);
String actualFirstName = ((String) getFieldValue(actual, "org.springframework.samples.petclinic.model.Person", "firstName"));
assertNull(actualFirstName);
String actualLastName = ((String) getFieldValue(actual, "org.springframework.samples.petclinic.model.Person", "lastName"));
assertNull(actualLastName);
Integer actualId = ((Integer) getFieldValue(actual, "org.springframework.samples.petclinic.model.BaseEntity", "id"));
assertNull(actualId);
}
Description
For Spring projects we use custom mocking strategy that is similar to
Mock other classes
, but may contain type replacements. It seems that we should add one more customization: mocking classes marked@Entity
is useless as they may be easily constructed with symbolic engine.It is better to start with an example where we mock entities now and we will not do it with new approach.