The following test fails with a NullPointerException
on the line usersRepo.save(user);
. I believe it's because when the test goes into the performProvision()
function the usersRepo
object is null
.
However, when the web service is actually running and the endpoint for my controller is hit, everything works fine and the database is updated.
Any idea why the test fails? My idea was that PAutoProvision
references the real database, whereas it should be dealing with the in-memory database so maybe there is some sort of conflict? I have also seen a lot of different examples with annotations set up differently, so I suppose that could be a problem too.
UsersRepo extends JpaRepository where PAutoProvision is a SQL table entity.
If this isn't enough information, I can provide the UsersRepo
, PAutoProvision
, and ProvisionController
classes if necessary.
The Service:
@Service
public class ProvisionService {
@Autowired
private UsersRepo usersRepo;
public String performProvision(UserData userData) {
try {
PAutoProvision user = new PAutoProvision(userData);
usersRepo.save(user); // OOTB CRUD repository functionality of springData to update/insert record data
return String.format("Success: User %s has been added to the database", userData.getUserId());
} catch (Exception e) {
e.printStackTrace();
System.out.println(e.toString());
System.out.println("\n\n Cannot perform the provisioning of the user " + userData.getUserId() + ": \n" + e.toString() + "\n\n");
}
return "problem";
}
}
The Test:
@RunWith(SpringRunner.class)
public class ProvisionServiceTest {
private ProvisionService provisionService;
@MockBean
private UsersRepo usersRepo;
@Before
public void setUp(){
provisionService = new ProvisionService();
}
@Test
public void performProvision_shouldPass() {
UserData userData = new UserData("userid", 30, 1, "spot", 1);
try {
String result = provisionService.performProvision(userData);
assertThat(result, is(equalTo("Success: User userid has been added to the database")));
} catch (Exception e) {
e.printStackTrace();
System.out.println(e.toString());
}
}
}
EDIT 1:
Adding @Autowired
and removing setUp()
method results in the following:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.autoprovision.ProvisionServiceTest': Unsatisfied dependency expressed through field 'provisionService'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.autoprovision.ProvisionService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
The given answer seems useful but just in case it can help someone, testing service is not so obvious in Spring (IMHO). The SpyBean
annotation turns out to be really handy:
@RunWith(SpringRunner.class)
public class ProvisionServiceTest {
@SpyBean
private ProvisionService provisionService;
}
Source : Spring Boot Reference - Testing
As JB Nizet already stated, the UserRepo
mock is not injected into the provisionService instance, because the provisionService instance is created in the setUp method with new
.
Your test should look like this:
@RunWith(SpringRunner.class)
public class ProvisionServiceTest {
@Autowired // let Spring instantiate the instance to test
private ProvisionService provisionService;
@MockBean
private UsersRepo usersRepo;
@Test
public void performProvision_shouldPass() {
UserData userData = new UserData("userid", 30, 1, "spot", 1);
String result = provisionService.performProvision(userData);
assertThat(result, is(equalTo("Success: User userid has been added to the database")));
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With