How to mock the #environment.getProperty('test.test') in thymeleaf test case - spring-boot

The code below
it is working perfectly fine in my application but I am having the test case for this thymeleaf html page as well it is throwing bean not found #envioronment.getProperty for my test case.
org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating SpringEL expression: "#environment.getProperty('css.specific.name')" (src/main/resources/templates/test_details.html)
EL1057E: No bean resolver registered in the context to resolve access to bean 'environment'
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {ThymesheetTestSpringContext.class})
public class ViewTest {
#Autowired
private ThymeleafTestEngine testEngine;
#Autowired
private TestMessageSource messageSource;
String templatePath = "src/main/resources/templates/test_details.html";
#Test
public void shouldDisplayVehicleInformationForIVFP() throws Exception {
helper.assertLocalization("test", "returned", "#test");
helper.assertLocalization("test1", "Frame number:123", "#test1");
}
}
public class ThHelper {
private ThymeleafTestEngine testEngine;
private TestMessageSource messageSource;
.....................................
private Callable<HtmlElements> view = () -> testEngine.process(templatePath, model);
private Function<Map<String, Object>, HtmlElements> viewWithModel = (model) -> testEngine.process(templatePath, model);
}

You have to autowire your Environment bean so that it can have instantiated object like below.
#Autowired
Environment environment
You can also set #Value annotated fields through ReflectionUtils from spring test framework
A typical setField would look like as specified below:
ReflectionUtils.setField(mockedServiceWhichNeedsValueSet, nameOfFiledToBeSet, valueToBeSet);

Related

Unit test #WebMvcTest NoSuchBeanDefinitionException

I am writing a test for a very simple standalone Controller:
#CrossOrigin(origins = "*", maxAge = 3600)
#RestController
public class TestController {
#PostMapping("/version")
public String getVersion() {
// String a = TUtil.TestUtil("ds");
String a = "a";
return a;
}
}
This controller only defines and returns a String, it is not dependent on any other classes.
Here is my test:
#RunWith(SpringRunner.class)
#WebMvcTest(TestController.class)
public class TestControllerTest {
#Autowired
private MockMvc mockMvc;
#Test
public void getVersion() throws Exception {
this.mockMvc.perform(MockMvcRequestBuilders.post("/version"))
.andExpect(MockMvcResultMatchers.status().is4xxClientError())
.andDo(MockMvcResultHandlers.print())
.andExpect(MockMvcResultMatchers.content().string("a"))
.andReturn();
}
}
then it gives a lot of errors, some of them are:
java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'ipArcuserauthMapper' defined in file [/Users/xy/Desktop/springweb/aaa/dccb/target/classes/com/dccb/tft/mapper/IpArcuserauthMapper.class]:
Invocation of init method failed;
nested exception is java.lang.IllegalArgumentException: Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required
It says I need to define a bean of type 'IpArcuserauthMapper' which has nothing remotely to do with the TestController.
In another case, if I use the SpringbootTest annotation, the problem can be solved:
#SpringBootTest(classes = {TftApplication.class})
#AutoConfigureMockMvc
#RunWith(SpringRunner.class)
I have no idea what is going on with #WebMvcTest(TestController.class)??
From what I know the WebMvcTest annotation only scans the class defined in the brackets.
Please help !!

Spring Testing Unsatisfied depencency NoSuchBeanDefinitionException

When I try to run my tests they all fail becaouse they can't find the bean of one of my classes.
Here are my codes which are used in the context:
The exception I get is this:
Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'testProtoAdminController' : Unsatisfied dependency expressed through constructor parameter 2; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'TestProtoCopyService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
TestProtoAdminControllerTest
#RunWith(SpringRunner.class)
#WebMvcTest(controllers = TestProtoAdminController.class)
public class TestProtoAdminControllerTest {
//Some used services
#Before
public void setUp() {
authenticatedMockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
#Test
#WithMockUser
public void testCopyProto() throws Exception {
authenticatedMockMvc.perform(post("/api/admin/{id}/copy", 1)
.contentType(MediaType.APPLICATION_JSON)
.content(asJson(new TestProtoBaseVo()))).andExpect(status().isOk());
}
//Some more tests which are not important in this case
TestProtoCopyService
#Service
public class TestProtoCopyServiceImpl implements TestProtoCopyService {
//Other services and repositories I have to use.
//Methods
}
TestProtoCopyService
public interface TestProtoCopyService {
#Transactional
void copyTestProto(long testProtoId, String sourceTenant, String targetTenant);
}
TestProtoAdminController
#RestController
#RequestMapping("/*")
public class TestProtoAdminController {
private TestProtoCopyService testProtoCopyService;
public TestProtoAdminController(TestProtoCopyService testProtoCopyService {
this.testProtoCopyService = testProtoCopyService;
}
When using #WebMvcTest Spring will prepare everything to test your web layer. This doesn't mean all your beans are scanned and are part of this test application context and ready to inject.
In general, you usually mock the service class of your controller with #MockBean and then use Mockito to specify its behavoir:
#RunWith(SpringRunner.class)
#WebMvcTest(controllers = TestProtoAdminController.class)
public class TestProtoAdminControllerTest {
#MockBean
private TestProtoCopyService mockedService
// the rest
#Before
public void setUp() {
authenticatedMockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
#Test
#WithMockUser
public void testCopyProto() throws Exception {
authenticatedMockMvc.perform(post("/api/admin/{id}/copy", 1)
.contentType(MediaType.APPLICATION_JSON)
.content(asJson(new TestProtoBaseVo()))).andExpect(status().isOk());
}
If you want Spring Boot to bootstrap the whole application context with every bean consider using #SpringBootTest. With this annotation, you can inject any bean to your application. The downside here is that you need to provide the whole infrastructure (database/queues/etc.) for your test.

Geting java.lang.IllegalStateException: Duplicate mock definition while using #MockBean in test case

I have one service class that I want to mock but while running the test I am Getting Caused by: java.lang.IllegalStateException: Duplicate mock definition [MockDefinition#482ba4b1 name = '', typeToMock = com.service.ThirdPartyService, extraInterfaces = set[[empty]], answer = RETURNS_DEFAULTS, serializable = false, reset = AFTER]
I have tried to create mock service using #MockBean at class level, field level, and used #Qualifier as well to resolve the issue
#Service
public class ThirdPartyService{
.......................
public String decrypt(String encryptedText) {
//third party SDK I am using
return Service.decrypt.apply(encryptedText);
}
.........
..............
}
#ComponentScan("com")
#PropertySource({"classpath:/api.properties", "classpath:/common.properties"})
#SpringBootConfiguration
#RunWith(SpringRunner.class)
#SpringBootTest(classes = {Application.class}, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
#Transactional
public class TestControllerTest extends IntegrationTest {
#MockBean
ThirdPartyService thirdPartyService;
#Before
public void initMocks(){
MockitoAnnotations.initMocks(this);
}
#Test
public void test() throws Exception {
when(ts.decrypt("encryptedText")).thenReturn("decryptedText")
Request req = Request.builder().name("name123").build();
//written performPost method in some other class
ResultActions action = performPost("/test", req);
action.andExpect(status().isOk());
}
}
public class IntegrationTest {
protected final Gson mapper = new Gson();
private MockMvc mvc;
#Autowired
private WebApplicationContext context;
public ObjectMapper objectMapper = new ObjectMapper();
#Before
public void setup() {
this.mvc = MockMvcBuilders.webAppContextSetup(context).apply(springSecurity()).build();
}}
When I am calling Thirdparty service decrypt method then it should return me decryptedText as a string. But getting duplicate mock definition error
I had the same issue.
Cause of this were test configuration file which was put somewhere else and it contained the mocked bean.
I have solved this by using #Autowired instead of #MockBean as this will result in autowiring the already mocked bean.
In my case the problem appeared after another dependency update and the reason was in the #SpringBootTest annotation referencing the same class twice:
#SpringBootTest(classes = {MyApplication.class, ApiControllerIT.class})
class ApiControllerIT extends IntegrationTestConfigurer {
// ...
}
#SpringBootTest(classes = {MyApplication.class, TestRestTemplateConfiguration.class})
public class IntegrationTestConfigurer {
// ...
}
I fixed it by removing #SpringBootTest annotation from the child class (ApiControllerIT).
In my case it was incorrect test class name that doesn't end with 'Test'.
If you have nested test classes try this:
#NestedTestConfiguration(OVERRIDE)
From Spring release notes: https://github.com/spring-projects/spring-framework/wiki/Upgrading-to-Spring-Framework-5.x#upgrading-to-version-53

Cucumber Spring and class configuration

I'm struggling with Cucumber and Spring configuration.
I'm writing selenium framework using Page Object Pattern, with BrowserFactory.
When I use #ComponentScan, #Component and #Autowire annotations everything works fine, but when I want to create a bit more complicated bean with #Bean annotation (BrowserFactory which registers few browser drivers) in #Configuration class it does not work, during debug I'm getting nulls on every single variable I'm trying to Autowire.
I'm using Spring 4.2.4, all cucumber dependencies in version 1.2.4.
Config:
#Configuration
public class AppConfig {
#Bean
#Scope("cucumber-glue")
public BrowserFactory browserFactory() {
BrowserFactory browserFactory = new BrowserFactory();
browserFactory.registerBrowser(new ChromeBrowser());
browserFactory.registerBrowser(new FirefoxBrowser());
return browserFactory;
}
#Bean(name = "loginPage")
#Scope("cucumber-glue")
public LoginPage loginPage() throws Exception {
return new LoginPage();
}
#Bean(name = "login")
#Scope("cucumber-glue")
public Login login() {
return new Login();
}
}
POP:
public class LoginPage extends Page {
public LoginPage() throws Exception {
super();
}
...
}
Page:
public class Page {
#Autowired
private BrowserFactory browserFactory;
public Page() throws Exception{
...
}
}
Login:
public class Login {
#Autowired
private LoginPage loginPage;
public Login(){}
...
}
Steps:
#ContextConfiguration(classes = {AppConfig.class})
public class LoginSteps {
#Autowired
Login login;
public LoginSteps(){
}
#Given("^an? (admin|user) logs in$")
public void adminLogsIn(Login.User user) throws Exception {
World.currentScenario().write("Logging in as " + user + "\n");
login.as(user);
}
}
Error:
cucumber.runtime.CucumberException: Error creating bean with name 'LoginSteps': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: Login LoginSteps.login; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'login': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private LoginPage Login.loginPage; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'loginPage' defined in AppConfig: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [LoginPage]: Factory method 'loginPage' threw exception; nested exception is java.lang.NullPointerException
And now for the fun part...
BrowserFactory in World class is properly Autowired!!
World:
public class World {
#Autowired
private BrowserFactory browserFactory;
...
}
So I'll answer my own question:)
Issue was that I was calling BrowserFactory inside of Page constructor.
Looks like this bean was not yet created and was causing NPEs.
In order to fix that I:
Added #Lazy annotation to configuration (all elements that use this configuration, both defined in that class and those which will be found by Scan will be created as Lazy)
Moved call to Browser Factory to #PostConstruct method
Two more things to increase readability of Spring config:
Added #ComponentScan to configuration
Classes with no constructor parameters are annotated with #Component and #Scope("cucumber-glue") annotation so bean creation can be removed from AppConfig.class

BeanCreationException on Spring TestNG PowerMock test

I'm getting BeanCreationException when using #AutoWired (Spring Annotation) and #PrepareForTest (PowerMock) and running my Spring enabled TestNG test.
I have a Spring controller, picked up via component scan.
I'm testing with TestNG, Mockito, and PowerMock.
I'm trying to spy on an auto wired controller thats autowired into the test, via: #AutoWired annotation.
Here's the beginning of the test class:
#PowerMockIgnore("*")
#WebAppConfiguration
#ContextConfiguration(locations = { "classpath:applicationContext-test.xml" })
#PrepareForTest(IWantAHamburgerController.class)
public class IWantAHamburgerControllerTest extends AbstractTestNGSpringContextTests {
#Autowired
private WebApplicationContext wac;
#Autowired
private MockHttpSession session;
#Autowired
private MockHttpServletRequest request;
#Autowired
private IWantAHamburgerController iWantAHamburgerController;
private MockMvc mockMvc;
#ObjectFactory
public IObjectFactory getObjectFactory() {
return new org.powermock.modules.testng.PowerMockObjectFactory();
}
#BeforeClass
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
// see the note at the bottom of this post about this line
//iWantAHamburgerController = (IWantAHamburgerController) applicationContext.getBean("iWantAHamburgerController");
}
I'm trying to test a GET method on IWantAHamburgerController. This is what the test looks like:
#Test
public void testGetHamburgerAfterAskingThisQuestion() throws Exception {
Principal p = PowerMockito.mock(Principal.class);
PowerMockito.when(p.getName()).thenReturn("oneofthefiveguys");
IWantAHamburgerController spy = PowerMockito.spy(iWantAHamburgerController);
PowerMockito.doReturn("oneofthefiveguys").when(spy).getUserName("oneofthefiveguys");
mockMvc.perform(get("/hamburgers/everythinghamburger.html")).andExpect(status().isOk())
.andExpect(view().name("jsp/hamburger/everythinghamburger"))
.andExpect(forwardedUrl("jsp/hamburger/everythinghamburger"));
PowerMockito.verifyPrivate(spy).invoke("initGrill", "oneofthefiveguys");
new org.mockito.internal.debugging.MockitoDebuggerImpl().printInvocations(spy);
}
Inside the test I want to spy on the autowired iWantAHamburgerController in order to verify that initGrill was called by the GET method on the controller.
If I remove #PrepareForTest(IWantAHamburgerController.class) I do not get a BeanCreationException, but then PowerMock doesn't work.
Note: I've tried to manually set the iWantAHamburgerController bean, but when I do, I get a ClassCastException.
Here's the full stack:
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name
'com.fiveguys.controllers.IWantAHamburgerControllerTest': Injection of
autowired dependencies failed; nested exception is
org.springframework.beans.factory.BeanCreationException: Could not
autowire field: private
com.fiveguys.controllers.IWantAHamburgerController
com.fiveguys.controllers.IWantAHamburgerControllerTest.iWantAHamburgerController;
nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type
[com.fiveguys.controllers.IWantAHamburgerController] found for
dependency: expected

Resources