Can not Autowire bean in Junit - java

I am trying to unit test a Controller Class with Junit. However, when I try to autowire my PlayerRepository interface, which extends crudRepository, it gives this error:
2018-12-06 21:59:39.530 ERROR 8780 --- [ main]
o.s.test.context.TestContextManager : Caught exception while
allowing TestExecutionListener
[org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener#78e117e3]
to prepare test instance
[edu.ceng.gameproject.player.PlayerControllerTest#4f704591]
(I did not put the entire error since it is very long.)
and it also says:
Caused by:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type 'edu.ceng.gameproject.player.PlayerRepository'
available: expected at least 1 bean which qualifies as autowire
candidate. Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
By the way, I can do the autowire in my controller to make changes on database. It just does not work in testing. Here is my code:
Controller Class:
#Controller // This means that this class is a Controller
#RequestMapping(path="/Player") // This means URL's start with /Player
(after Application path)
public class PlayerController {
#Autowired
private PlayerRepository playerRepository;
}
Here is the PlayerRepsitory interface:
#Repository
public interface PlayerRepository extends CrudRepository<Player, String> {
}
Abstract test class where I do the autowiring :
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(classes = Main.class)
#WebAppConfiguration
public abstract class GameProjectBackEndApplicationTests {
protected MockMvc mvc;
#Autowired
WebApplicationContext webApplicationContext;
#Autowired
PlayerRepository playerRepository;
protected void setUp() {
mvc =
MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
}
PlayerControllerTest class where I use the autowired playerRepository:
public class PlayerControllerTest extends GameProjectBackEndApplicationTests
{
#Override
#Before
public void setUp() {
super.setUp();
}
#Test
public void test_getUsersList_withOk() throws Exception {
String uri = "/Player/all";
// Create user in the database
Player createdUser = playerRepository.save(new Player("testUser",
"testPassword"));
MvcResult mvcResult = mvc.perform(MockMvcRequestBuilders.get(uri)
.accept(MediaType.APPLICATION_JSON_VALUE)).andReturn();
// check if status is 200 - OK
int status = mvcResult.getResponse().getStatus();
assertEquals(200, status);
String content = mvcResult.getResponse().getContentAsString();
Player[] playerList = super.mapFromJson(content, Player[].class);
// check if list has actually any user
assertTrue(playerList.length > 0);
// check returned list has user that we created
boolean contains = false;
for (int i = 0; i < playerList.length; i++) {
if
(createdUser.getUsername().equals(playerList[i].getUsername())
&&
createdUser.getPasswd().equals(playerList[i].getPasswd())) {
contains = true;
}
}
// assert there is a user that we created
assertTrue(contains);
//delete created user
playerRepository.deleteById(createdUser.getUsername());
}
}
Thanks in advance.

As I said in the comments, use #MockBean to inject a mock for every dependency needed in your controller. Your test class will look like this.
#RunWith(SpringRunner.class)
#SpringBootTest(classes = Main.class)
#WebAppConfiguration
public class GameProjectBackEndApplicationTests {
private MockMvc mvc;
#Autowired
private WebApplicationContext webApplicationContext;
#MockBean
private PlayerRepository playerRepository;
#Before
public void setUp() {
mvc =
MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
// Mock calls to PlayerRepository
// Mockito.when(playerRepository.getEntries(1)).thenReturn(myList);
}
#Test
public void myTest() {
....
}
}
Also, I don't really recommend using inheritance for your tests. It is better to have everything in one place.

Related

MockMvc Spring Boot springSecuirtyChainCannotBeNull issue

Can someone point me to what could be wrong in below code. It is a boot spring 2.6.7 application. When test profile is running, it throws error for all tests like below.
java.lang.IllegalStateException: springSecurityFilterChain cannot be null. Ensure a Bean with the name springSecurityFilterChain implementing Filter is present or inject the Filter to be used
#AutoConfigureMockMvc
#SpringBootTest(classes = some.class)
#ActiveProfiles("test")
public class someTest {
#Autowired
private MockMvc mvc;
#Autowired
private WebApplicationContext webAppContext;
#MockBean
private SomeBean someBean;
#SpyBean
private SomeSpyBean someSpyBean;
#BeforeEach
public void setup() {
mvc = MockMvcBuilders
.webAppContextSetup(webAppContext)
.apply(springSecurity())
.build();
}
#Test
public void SomeTest1() throws Exception {
String text = "text1";
when(someBean.findStuff(text).thenReturn(Optional.of(new Thingie()));
mvc.perform(multipart("/api/somepath/")
.andExpect(status().isNotFound());
verify(someSpyBean).doStuff();
}
#Test
public void SomeTest2() throws Exception {
String text = "text2";
when(someBean.findStuff(text).thenReturn(Optional.of(new Thingie()));
mvc.perform(multipart("/api/somepath/")
.andExpect(status().isFound());
verify(someSpyBean).doStuff();
}
}

ApplicationContext returns null in SpringBootTest run with SpringRunner.class

I have a problem of running my Test class. It returns "org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 't.c.i.s.se.Sfts' available: expected single matching bean but found 2: sftsImpl,sfts" this exception after I run it.
Here's my test class;
#RunWith(SpringRunner.class)
#SpringBootTest(classes = Sfta.class)
public class SftaTests {
#Autowired
ApplicationContext ac;
#Test
public void contextLoads() {
Sfts sfts= ac.getBean(Sfts.class);
assertTrue(Sfts instanceof SftsImpl);
}
}
And my other classes are like;
public interface Sfts {
public void process();
}
#Service
#Component
public class SftsImpl implements Sfts {
#Autowired
private GlobalConfig globalConfig;
#Autowired
private Ftr ftr;
private Fc fc;
#Async
#Scheduled(initialDelayString = "${s.f.t.m}", fixedRateString = "${s.f.t.m}")
public void process() {
int hod = DateTime.now().getHourOfDay();
if (hod != 6){
fc = new Fc(globalConfig, ftr);
fc.control();
}
}
}
Why I get the error after running the test application?
Try to remove #Component annotation from the SftsImpl bean.
#Service is enough to register a bean.
Also if you just want to test your bean - getting it from ApplicationContext maybe is not the best option.
Code example of a unit test without using ApplicationContext:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = Sfta.class)
public class SftaTests {
#Autowired
Sfts sfts;
#Test
public void testAsync() {
sfts.process();
// do assertions here
}
}

Why #MockBean does not mock my target repository class (returns null)?

Here is the class I want to test
#Component
public class PermissionCheck {
#Autowired
private MyEntityRepository myEntityRepository;
public boolean hasPermission(int myEntityID) {
MyEntity myEntity = myEntityRepository.findById(myEntityId);
return myEntity != null;
}
}
Here is the test class
#RunWith(SpringRunner.class)
public class PermissionCheckTests {
#MockBean
private MyEntityRepository myEntityRepository;
private PermissionCheck permissionCheck;
#Before
public void before() {
this.permissionCheck = new PermissionCheck();
}
#Test
public void shouldHasPermission() {
MyEntity myEntity = new MyEntity();
when(this.myEntityRepository.findById(any())).thenReturn(myEntity);
assertTrue(this.permissionCheck.hasPermission(0));
}
}
And when I run this test I got
java.lang.NullPointerException
at PermissionCheck.hasPermission(PermissionCheck.java:line1)
at PermissionCheckTests.shouldHasPermission(PermissionCheckTests.java:line2)
In the above, line1 and line2 refer to these two lines
MyEntity myEntity = myEntityRepository.findById(myEntityId);
assertTrue(this.permissionCheck.hasPermission(0));
And using debugger I see that when entering PermissionCheck.hasPermission from PermissionCheckTests.shouldHasPermission, the repository field
#Autowired
private MyEntityRepository myEntityRepository;
is null.
I created these classes by referring to others existing codes, from different places, and without really understanding how to the annotations (partially due to running out of time), so if someone can tell me not only how to fix, but also why I'm wrong, I would really appreciate it!
Edit:
I made the change suggested by #Nikolas Charalambidis (thank you!), so my PermissionCheck class now looks exactly like
#RunWith(SpringRunner.class)
public class PermissionCheckTests {
#Autowired // you need to autowire
private PermissionCheck permissionCheck; // and it uses #MockBean dependency
#MockBean // if no such #MockBean exists
private MyEntityRepository myEntityRepository; // the real implementation is used
#Test
public void shouldHasPermission() {
MyEntity myEntity = new MyEntity();
when(this.myEntityRepository.findById(any())).thenReturn(myEntity);
assertTrue(this.permissionCheck.hasPermission(0));
}
}
But I then got the following exception
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'PermissionCheckTests':
Unsatisfied dependency expressed through field 'permissionCheck';
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type 'PermissionCheck' available:
expected at least 1 bean which qualifies as autowire candidate.
Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true),
#org.springframework.beans.factory.annotation.Qualifier(value="")}
With a little bit search, from this SO answer, I feel like I should not #Autowired PermissionCheck, since it is a class, not an interface.
Does that mean I have to create an interface, #Autowired it and let PermissionCheck implement it? It seems redundant to me, since I don't see why I need such an interface. Is there a way to make it work without creating a new interface which I will solely use for this purpose?
The instance of class PermissionCheck is not properly injected. The tests use the Spring container in the same way as the production code. The following line would not inject the myEntityRepository.
this.permissionCheck = new PermissionCheck();
Spring: NullPointerException occurs when including a bean partly answers your question. You need to #Autowire the thing.
The Spring test context is no different. As long as #MockBean MyEntityRepository exists as a mocked bean, the PermissionCheck will be autowired in the standard way using the mocked class in precedence over the existing bean in the test scope.
#RunWith(SpringRunner.class)
public class PermissionCheckTests {
#Autowired // you need to autowire
private PermissionCheck permissionCheck; // and it uses #MockBean dependency
#MockBean // if no such #MockBean exists
private MyEntityRepository myEntityRepository; // the real implementation is used
#Test
public void shouldHasPermission() {
MyEntity myEntity = new MyEntity();
when(this.myEntityRepository.findById(any())).thenReturn(myEntity);
assertTrue(this.permissionCheck.hasPermission(0));
}
}
in my case i was using lombok i was added #NoArgsConstructor
to the class that that i had injected my repository.
#Component
#AllArgsConstructor
#NoArgsConstructor // what cuased the null pointer
public class ParcelUtil {
private final Logger log = LoggerFactory.getLogger(OrderEventConsumer.class);
private ParcelRepository parcelRepository;
}
my test:
#SpringBootTest
#DirtiesContext
public class OrderEventConsumerTest extends SpringBootEmbeddedKafka {
#MockBean
private ParcelRepository parcelRepository;
}
#Test
public void update_parcel_inride_to_delivered_nxb() throws JsonProcessingException {
//given
List<Parcel> parcels = DataUtil.createParcel_inride_and_draft_nxb();
Mockito
.when(parcelRepository.findFirstByParcelGroupId("12"))
.thenReturn(Optional.ofNullable(parcels.get(0))); //where i got null pointer
}
}

Unresolved dependency in UnitTesting Spring Boot

I getting the following error when trying to write a unit test for CircuitBreaker code example.
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name
'com.foosball.team.Service.TeamServiceUnitTest': Unsatisfied
dependency expressed through field 'registry'; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type
'io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry'
available: expected at least 1 bean which qualifies as autowire
candidate. Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
TeamService:
#Service
public class TeamService {
#Autowired
private ITeamRepository teamRepository;
#Autowired
private PlayerClient playerClient;
Logger logger = LoggerFactory.getLogger(TeamService.class);
.
.
.
TeamServiceUnitTest:
#SpringBootTest(classes = {
TeamService.class
})
#RunWith(SpringRunner.class)
#DirtiesContext
public class TeamServiceUnitTest extends AbstractCircuitBreakerTest {
#MockBean
private ITeamRepository teamRepository;
#MockBean
private PlayerClient playerClient;
#Autowired
private TeamService service;
private TeamEntity teamEntity;
private Logger logger = LoggerFactory.getLogger(TeamServiceUnitTest.class);
#Before
public void setUp(){
teamEntity = new TeamEntity();
teamEntity.setId(1L);
teamEntity.setPlayerOne("One");
teamEntity.setPlayerTwo("Two");
teamEntity.setPlayerThree("Three");
teamEntity.setPlayerFour("Four");
}
#Test
#DisplayName("when Player Client Fails 11 Times Then CircuitBreaker Should Be In OPEN State")
public void whenPlayerClientFailsElevenTimesThenCircuitBreakerShouldBeInOPENState(){
//Given
when(teamRepository.findAll()).thenReturn(new ArrayList<>());
when(playerClient.get(Mockito.anyString())).thenThrow(new RuntimeException());
//When
for(int i=0; i<11; i++){
try {
service.addTeam(teamEntity);
} catch (Exception ignore) {
logger.info(ignore.getClass().getName());
}
}
//Then
checkHealthStatus(BACKEND_B, CircuitBreaker.State.OPEN);
}
}
Ref Class:
public class AbstractCircuitBreakerTest {
protected static final String BACKEND_A = "backendA";
protected static final String BACKEND_B = "playerClientCircuitBreaker";
#Autowired
protected CircuitBreakerRegistry registry;
#Before
public void setup(){
transitionToClosedState(BACKEND_A);
transitionToClosedState(BACKEND_B);
}
protected void checkHealthStatus(String circuitBreakerName, CircuitBreaker.State state) {
CircuitBreaker circuitBreaker = registry.circuitBreaker(circuitBreakerName);
assertThat(circuitBreaker.getState()).isEqualTo(state);
}
protected void transitionToOpenState(String circuitBreakerName) {
CircuitBreaker circuitBreaker = registry.circuitBreaker(circuitBreakerName);
if(!circuitBreaker.getState().equals(CircuitBreaker.State.OPEN)){
circuitBreaker.transitionToOpenState();
}
}
protected void transitionToClosedState(String circuitBreakerName) {
CircuitBreaker circuitBreaker = registry.circuitBreaker(circuitBreakerName);
if(!circuitBreaker.getState().equals(CircuitBreaker.State.CLOSED)){
circuitBreaker.transitionToClosedState();
}
}
}
Ref Project: https://github.com/resilience4j/resilience4j-spring-boot2-demo
Proposed Soln Discussion: https://github.com/resilience4j/resilience4j-spring-boot2-demo/issues/33
Proposed Soln Project: https://github.com/shah-smit/resilience4j-spring-boot2-demo-maven
Looks like CircuitBreakerRegistry you're trying to autowire in you test is a factory class, not a bean. Instead of
#Autowired
protected CircuitBreakerRegistry registry;
Try:
protected CircuitBreakerRegistry registry = CircuitBreakerRegistry.ofDefaults()
Here's an answer about not working tests.
Few things here:
1. Using CircuitBreakerRegistry.ofDefaults() creates new instance of object each time so this way the CircuitBreakerRegistry objects you're using in AbstractCircuitBreakerTest and HomeService are different instances. You should probably go back to #Autowired annotation but first you need to define bean of CircuitBreakerRegistry like this:
public class CircuitBreakerConfiguration {
#Bean
public CircuitBreakerRegistry circuitBreakerRegistry() {
return CircuitBreakerRegistry.ofDefaults();
}
}
You're using #RunWith(SpringRunner.class) but it's just Junit annotation and it does not initialize Spring Context in your test. You're autowiring a bean in your test so you need Spring Context. For this add also #SpringBootTest annotation.
You're expecting the registry BACKEND_A state to change to OPEN after 11 calls of service.getGreeting() method but I cannot see any usage of transitionToOpenState method.

Creating beans when Autowiring with Spring

I am trying to write a test for my controller. When the web service is running everything works fine. However, when I run the test I get:
Error creating bean with name 'Controller': Unsatisfied dependency expressed through field 'service'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.prov.Service' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
As you can see below, I believe have everything correctly Autowired and my project structure is correctly set up so that the component scanner can find the annotations properly, yet I still get this error.
Controller:
#RestController
#RequestMapping("/api")
public class Controller {
#Autowired
private Service service;
#JsonView(Views.All.class)
#RequestMapping(value = "/prov/users", method = RequestMethod.POST)
#ResponseBody
public CommonWebResponse<String> handleRequest(#RequestBody UserData userData) {
return service.prov(userData);
}
}
Service:
#Service
public class Service {
#Autowired
private Repo repo;
#Autowired
private OtherService otherService;
public CommonWebResponse<String> prov(UserData userData) {
// do stuff here
return new SuccessWebResponse<>("Status");
}
}
Controller Test:
#RunWith(SpringRunner.class)
#WebMvcTest(
controllers = Controller.class,
excludeFilters = {
#ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE,
value = {CorsFilter.class, AuthenticationFilter.class}
)
}
)
#AutoConfigureMockMvc(secure = false)
public class ControllerTest {
public static final MediaType APPLICATION_JSON_UTF8 = new MediaType(MediaType.APPLICATION_JSON.getType(), MediaType.APPLICATION_JSON.getSubtype(), Charset.forName("utf8"));
#Autowired
private MockMvc mvc;
#Test
public void connectToEndpoint_shouldReturnTrue() {
UserData userData = new UserData("a", "bunch", "of", "fields");
try {
mvc.perform(post("/api/prov/users").contentType(APPLICATION_JSON_UTF8)
.content(asJsonString(userData))
.accept(MediaType.ALL))
.andExpect(status().isOk());
} catch (Exception e) {
Assert.fail();
}
}
}
The Controller class autowires your Service class. Therefore, testing the Controller class requires existence of your Service class because Controller depends on creating a bean of type Service. This means you either have to #Autowired your service class into your test, or (preferably) mock it using something like Mockito.
(edit with code example):
#RunWith(SpringRunner.class)
#WebMvcTest(Controller.class)
public class ControllerTest {
#MockBean
private Service service
#Autowired
private MockMvc mvc;
#Test
public void foo() {
String somePayload = "Hello, World";
String myParams = "foo";
when(service.method(myParams)).thenReturn(somePayload);
mvc.perform(get("my/url/to/test").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$", is(equalTo("Hello, World"))));
}
}
Do note that this example uses Hamcrest for things like is() and equalTo()

Categories