Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mock for dependent list is created but not injected into entity #2637

Open
alisevych opened this issue Oct 3, 2023 · 4 comments
Open

Mock for dependent list is created but not injected into entity #2637

alisevych opened this issue Oct 3, 2023 · 4 comments
Assignees
Labels
comp-codegen Issue is related to code generator comp-spring Issue is related to Spring projects support ctg-bug Issue is a bug

Comments

@alisevych
Copy link
Member

Description

linkedListSpy is created and configured, but not injected into Entity under test

To Reproduce

  1. Install -IU- UnitTestBot plugin in IntelliJ IDEA
  2. Open spring-petclinic
  3. Generate Unit tests for Owner with PetClinicApplication configuration
  4. Run the tests

Expected behavior

No NPE should be thrown from get-methods of the entity before assertions.

Actual behavior

There are several tests throwing NPE when getting fields of actual Pet.

Screenshots, logs

	@Test
	@DisplayName("getPet: id = zero (mutated from min)")
	public void testGetPetWithCornerCase5() throws ClassNotFoundException, IllegalAccessException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException {
		owner.setLastName("-3");
		Pet petMock = mock(Pet.class);
		(when(petMock.isNew())).thenReturn(true);
		linkedListSpy.add(petMock);
		Pet petMock1 = mock(Pet.class);
		(when(petMock1.isNew())).thenReturn(false);
		(when(petMock1.getId())).thenReturn(0);
		linkedListSpy.add(petMock1);
		Pet petMock2 = mock(Pet.class);
		linkedListSpy.add(petMock2);
		Pet petMock3 = mock(Pet.class);
		linkedListSpy.add(petMock3);
		Pet petMock4 = mock(Pet.class);
		linkedListSpy.add(petMock4);

		Pet actual = owner.getPet(0);

		LocalDate actualBirthDate = actual.getBirthDate();
		assertNull(actualBirthDate);

		PetType actualType = actual.getType();
		assertNull(actualType);

		Set actualVisits = ((Set) getFieldValue(actual, "org.springframework.samples.petclinic.owner.Pet", "visits"));
		assertNull(actualVisits);

		String actualName = actual.getName();
		assertNull(actualName);

		Integer actualId = actual.getId();
		assertNull(actualId);

	}

image

image

Environment

IntelliJ IDEA version - Community 2023.2
Project - Maven
JDK - 17

Additional context

When debugging, linkedListSpy is returning expected values.
There is pet returning isNew()=false and getId()=0.
But owner.getPets() returns empty list.

@alisevych alisevych added ctg-bug Issue is a bug comp-codegen Issue is related to code generator priority-blocker Bug blocking some of the main features comp-spring Issue is related to Spring projects support labels Oct 3, 2023
@alisevych alisevych added this to the October Release milestone Oct 3, 2023
@alisevych alisevych removed the priority-blocker Bug blocking some of the main features label Oct 3, 2023
@EgorkaKulikov
Copy link
Collaborator

EgorkaKulikov commented Oct 3, 2023

Investigated with @tepa46 and @Vassiliy-Kudryashov - looks like a very strange case.

There is no obvious reasons why Spring cannot inject this Spy into the instance under test. It can be manually fixed if we replace ArrayList with ArrayList<Pet>, but we cannot generate such code due to generics support limitations in UnitTestBot.

Tomorrow I'm going to ask other collegues if they see the reasons of autowiring problems here. If we clarify it, it may be possible to use some fallback as we do when there are several lists of one type in project.

@EgorkaKulikov
Copy link
Collaborator

EgorkaKulikov commented Oct 4, 2023

It seems to be a bug in Mockito.

Consider the following test

        @Test
	@DisplayName("getPet: compId.equals(id) : True -> return pet")
	public void testGetPet_CompIdEquals() throws Exception {
		Pet petMock = mock(Pet.class);
		(when(petMock.isNew())).thenReturn(false);
		(when(petMock.getId())).thenReturn(-255);
		pets.add(petMock);
		pets.add(null);
		pets.add(null);
		Integer id = -255;

		Pet actual = owner.getPet(id);

		assertNull(actual.getBirthDate());
		assertNull(actual.getType());
		Set actualVisits = ((Set) getFieldValue(actual, "org.springframework.samples.petclinic.owner.Pet", "visits"));
		assertNull(actualVisits);
		assertNull(actual.getName());
		assertNull(actual.getId());
	}

This version does not work

        @InjectMocks
	private Owner owner;

	@Spy
	private ArrayList pets;

This version works

        @InjectMocks
	private Owner owner;

	private ArrayList pets = Mockito.spy(new ArrayList());

However, in accordance with @Spy documentation, it must be the same.

Seems to be a generics support problems in @InjectMocks. There are some other known issues about it, like mockito/mockito#1066.

@alisevych
Copy link
Member Author

@EgorkaKulikov
Can we generate code like it is in your second example?
With explicit spy creation?

@EgorkaKulikov
Copy link
Collaborator

@SPY annotation was constructed as a smart syntax and guidelines recommend it. After that, here we know one seldom bug, I have no idea how many potential problems are hidden in it. It can be investigated, but it will take time.

@alisevych alisevych removed this from the October Release milestone Oct 4, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
comp-codegen Issue is related to code generator comp-spring Issue is related to Spring projects support ctg-bug Issue is a bug
Projects
Status: Todo
Development

No branches or pull requests

2 participants