Spring integration test with PowerMockito + TestNG leads to InvocationTargetException - spring

I'm trying to mock a static method with PowerMockito in an integration test with TestNG, but no joy so far.
#PrepareForTest({ HttpCommonClientUtils.class })
public class LiveChannelServiceTestNg extends LiveBaseTestNg {
#Autowired
private LiveChannelShareService liveChannelService;
#Resource(name = "liveSettingService")
private LiveSettingShareService liveSettingService;
#Autowired
private VCloudHelper vcloudHelper;
#ObjectFactory
public IObjectFactory getObjectFactory() {
return new org.powermock.modules.testng.PowerMockObjectFactory();
}
static String result = "{\\\"cid\\\":\\\"0aba025de6604ccb931bd9868bddba9a\\\",\\\"duration\\\":120,\\\"format\\\":0,\\\"gmtCreate\\\":1486378732486,\\\"hlsPullUrl\\\":\\\"http://pullhls03f9fed7.live.126.net/live/0aba025de6604ccb931bd9868bddba9a/playlist.m3u8\\\",\\\"httpPullUrl\\\":\\\"http://flv03f9fed7.live.126.net/live/0aba025de6604ccb931bd9868bddba9a.flv?netease=flv03f9fed7.live.126.net\\\",\\\"id\\\":1,\\\"name\\\":\\\"直播频道1\\\",\\\"needRecord\\\":1,\\\"pushUrl\\\":\\\"rtmp://p03f9fed7.live.126.net/live/0aba025de6604ccb931bd9868bddba9a?wsSecret=e5cf3b5c060271fd23ba56469a803a99&wsTime=1486378731\\\",\\\"referType\\\":0,\\\"rtmpPullUrl\\\":\\\"rtmp://v03f9fed7.live.126.net/live/0aba025de6604ccb931bd9868bddba9a\\\",\\\"status\\\":0,\\\"type\\\":0}";
static String cid = "0aba025de6604ccb931bd9868bddba9a";
#BeforeClass
public void setUp() throws Exception {
/* 公用的环境初始化... */
}
#BeforeMethod
public void testSetUp() throws Exception {
}
#Test
public void test_static() {
String result = "{\"cid\":\"0aba025de6604ccb931bd9868bddba9a\",\"duration\":120,\"format\":0,\"gmtCreate\":1486378732486,\"hlsPullUrl\":\"http://pullhls03f9fed7.live.126.net/live/0aba025de6604ccb931bd9868bddba9a/playlist.m3u8\",\"httpPullUrl\":\"http://flv03f9fed7.live.126.net/live/0aba025de6604ccb931bd9868bddba9a.flv?netease=flv03f9fed7.live.126.net\",\"id\":1,\"name\":\"直播频道1\",\"needRecord\":1,\"pushUrl\":\"rtmp://p03f9fed7.live.126.net/live/0aba025de6604ccb931bd9868bddba9a?wsSecret=e5cf3b5c060271fd23ba56469a803a99&wsTime=1486378731\",\"referType\":0,\"rtmpPullUrl\":\"rtmp://v03f9fed7.live.126.net/live/0aba025de6604ccb931bd9868bddba9a\",\"status\":0,\"type\":0}";
PowerMockito.mockStatic(HttpCommonClientUtils.class);
PowerMockito.when(HttpCommonClientUtils.getHtmlByPostMethod(Matchers.any(HttpClient.class),
Matchers.any(HttpDataProvider.class))).thenReturn(result);
LiveChannelDto dto = liveChannelService.getOrGenerateChannleByBindInfo(0, 1, 101L);
Assert.assertEquals(cid, dto.getCid());
}
When I run this test, a InvocationTargetException is appear

Related

SpringTest service class with parameterised constructor using MockitoServer

Background
I have a Test class having some unit tests that started failing after I made some changes in #Service class
#Service
public class WeatherService {
Environment Env
// I added this new autowired field as I created a new component WeatherUtil
#Autowired
WeatherUtil weatherUtil;
public WeatherService(Environment env) {
this.env = env;
}
}
Note that there's no default constructor
#Component
public class WeatherUtil {
// reads api properties from application.yml
#Autowired
private ApiProperties apiProperties;
#PostConstruct
private prepareMapOfProps(){
Map<String, Object> mapOfLatLong = apiProperties.getLatLong();
doSomething(mapOfLatLong);
}
private doSomething(Map<String, Object> mapOfLatLong){...}
}
The testClass definition is as below.
#Tag("unit")
#ExtendWith(MockitoExtension.class)
class TestWeatherApiService {
Environment env;
private static MockWebServer mockServer;
WeatherService weatherService;
#BeforeAll
public static void generalSetup() throws IOException {
mockServer = new MockWebServer();
mockServer.start();
}
#AfterAll
public static void generalTeardown() throws IOException {
mockServer.shutdown();
}
#BeforeEach
public void setup() {
when(env.getProperty("api.disable_ssl_certificate_validation", Boolean.class, false)).thenReturn(true);
weatherService = new WeatherService(env);
}
#Test
public void test1(){
// this test was working fine
mockServer.enqueue(new MockResponse().setBody("[]").addHeader("Content-Type", "application/json"));
// lat,ln set to someValue
weatherService.getWeather(lat, ln);
}
}
I have no clue what's going on as the application is running fine but the test has broken and not sure how to recover as the stacktrace shows Exception in other package.
Any idea on what minimal change can fix this?

Spring JUnit 5 ExtendWith TestContainer

I'm trying to reutilize a container and I'm trying to use JUnit5 ExtendWith feature but I'm still getting:
Connection to localhost:5432 refused.
If I have the same logic inside each test everything works as expected.
#Testcontainers
#SpringBootTest
#ExtendWith({PostgresTestContainersExtension.class})
public class ApplicationJUnit5Test {
#Autowired
private HeroClassicJDBCRepository repositoryUnderTest;
#Test
public void test1() {
System.out.println("junit version: " + Version.id());
Collection<Hero> heroes = repositoryUnderTest.allHeros();
assertThat(heroes).hasSize(1);
repositoryUnderTest.addHero(new Hero("bb", "bb"));
Collection<Hero> heroesAfter = repositoryUnderTest.allHeros();
assertThat(heroesAfter).hasSize(2);
}
}
Extention:
public class PostgresTestContainersExtension implements BeforeAllCallback,
BeforeTestExecutionCallback {
private static final String IMAGE_NAME = "registry.mycomp.com/db/mariadb:10.4.11";
#DynamicPropertySource
static void properties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", container::getJdbcUrl);
registry.add("spring.datasource.password", container::getPassword);
registry.add("spring.datasource.username", container::getUsername);
}
#Container
public static PostgreSQLContainer container = new PostgreSQLContainer()
.withUsername("duke")
.withPassword("password")
.withDatabaseName("test");
#Override
public void beforeAll(ExtensionContext extensionContext) {
startContainerIfNeed();
}
#Override
public void beforeTestExecution(ExtensionContext extensionContext) {
startContainerIfNeed();
}
public void startContainerIfNeed() {
if (!container.isRunning()) {
container.start();
}
}
}
As far as I know #DynamicPropertySource can only be used in the test class itself or a superclass. You’ll have to move the properties method over.

PowerMock whenNew Problem On Spring Component Constructor

I have a Spring Service like below:
#Service
public class SendWithUsService
{
private SendWithUs mailAPI;
public SendWithUsService()
{
this.mailAPI = new SendWithUs();
}
public void sendEmailEvent(Dto data)
{
try
{
SendWithUsSendRequest request = new SendWithUsSendRequest()...;
mailAPI.send(request);
}
catch (Exception e)
{
...
}
}
}
And my test code look like below:
#RunWith(PowerMockRunner.class)
#PowerMockIgnore({"javax.net.ssl.*"})
#PrepareForTest(SendWithUsService.class)
public class SendWithUsServiceTest
{
#InjectMocks
private SendWithUsService sendWithUsService;
#Mock
private SendWithUs mailAPI;
#Test
public void sendEmailEvent_successfully() throws Exception
{
whenNew(SendWithUs.class).withAnyArguments().thenReturn(mailAPI);
Dto emailData = ...;
sendWithUsService.sendEmailEvent(emailData);
...
}
}
In here, PowerMock whenNew method doesn't work. But when I call it outside of constructor like inside the sendEmailEvent method, it is triggered.
Is there a way to handle it?
Works:
public void sendEmailEvent(Dto data)
{
this.mailAPI = new SendWithUs();
...
}
Not works:
public SendWithUsService()
{
this.mailAPI = new SendWithUs();
}
I've solved it like below:
#RunWith(PowerMockRunner.class)
#PowerMockIgnore({"javax.net.ssl.*"})
#PrepareForTest(SendWithUsService.class)
public class SendWithUsServiceTest
{
#InjectMocks
private SendWithUsService sendWithUsService;
#Mock
private SendWithUs mailAPI;
#Before
public void setUp() throws Exception {
whenNew(SendWithUs.class).withAnyArguments().thenReturn(mailAPI);
MockitoAnnotations.initMocks(this);
}
#Test
public void sendEmailEvent_successfully() throws Exception
{
Dto emailData = ...;
sendWithUsService.sendEmailEvent(emailData);
...
}
}

Unable to mock a method with Mockito and Spring

I have a class JobDelegate for which i am writing unit tests using mockito. I am unable to mock the HTTPOperations class. I have tried using setter injection from test class as well. But it does not work. Below the latest revision of the code. I tried using Power mock. but none of them was helpful. I am unable to predict which is going wrong.
Unit Test code
#ContextConfiguration(locations= "file:src/main/webapp/WEB-INF/spring-
context.xml")
#RunWith(SpringJUnit4ClassRunner.class)
//#RunWith(PowerMockRunner.class)
/#PowerMockIgnore({ "javax.xml.*", "org.xml.*", "org.w3c.*" })
//#PrepareForTest({ HTTPOperations.class})
public class JobSubmissionDelegateTest{
private static Logger LOGGER = null;
private JobDelegate jobDelegate ;
private JobManager jobImpl;
#InjectMocks
private HTTPOperations operations;
//#Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
#Before
public void setupTests() {
jobDelegate = new JobDelegate();
jobManager = new DBJobManagerImpl();
operations = new HTTPOperations();
jobManager.setHttpOperations(operations);
jobSubmissionDelegate.setJobImpl(jobManager);
//HTTPOperations httpOperationsSpy =spy(HTTPOperations.class);
//doReturn("{\"response\":\"{\\\"run_id\\\":32423423}\\n\"}").when(myClassSpy).method1();
MockitoAnnotations.initMocks(this);
}
#Test
public void testExecuteJob() throws IOException {
// PowerMockito.mockStatic(HTTPOperations.class);
Mockito.when(operations.submitHttpPostRequest(any(), anyString())).thenReturn("{\"response\":\"{\\\"run_id\\\":32423423}\\n\"}");
//System.out.println("==>"+operations.submitHttpPostRequest(null, ""));
...........
int runID = jobDelegate.executeJob(jobDetails);
System.out.println("Run ID here " + runID);
}
}
public class JobDelegate {
// This is an interface.. and the implementation is passed from spring-
context.xml
#Autowired
private JobManager jobImpl;
public int executeJob(JobDTO jobDto) {
............
return jobImpl.runBatchJob(jobDto);
}
}
public class DBJobManagerImpl implements JobManager{
#Autowired
private URIUtils uriUtils;
#Autowired
private HTTPOperations httpOperations;
#Override
public int runBatchJob(JobDTO jobDto) throws Exception {
UriComponentsBuilder uri = uriUtils.createURI(ConfigUtil.getUrI());
String response = httpOperations.submitHttpPostRequest(uri, runSubmitJson);
System.out.println("Response ==> " +response);
.................
}
}
I was able to resolve the issue using PowerMock.
Below the code
#RunWith(PowerMockRunner.class)
#ContextConfiguration(locations= "file:src/main/webapp/WEB-
INF/Enrichment_Context.xml")
#PowerMockRunnerDelegate(SpringJUnit4ClassRunner.class)
#PowerMockIgnore({ "javax.xml.*", "org.xml.*", "org.w3c.*",
"javax.management.*" })
#PrepareForTest({ HTTPOperations.class})
public class JobDelegateTest {
#Autowired
private JobDelegate jobSubmissionDelegate;
#Test
public void testExecuteJob() throws IOException {
PowerMockito.mockStatic(HTTPOperations.class);
PowerMockito.when(HTTPOperations.submitHttpPostRequest(Mockito.any(),
Mockito.anyString())).thenReturn("{\"response\":\"{\\\"run_id\\\":32423423}\\n\"}");
...................
int runID = jobSubmissionDelegate.executeJobSubmission(jobDetails);
}
}

JUNIT - Null pointer Exception while calling findAll in spring Data JPA

I am new to Junits and Mockito, I am writing a Unit test class to test my service class CourseService.java which is calling findAll() method of CourseRepository.class which implements CrudRepository<Topics,Long>
Service Class
#Service
public class CourseService {
#Autowired
CourseRepository courseRepository;
public void setCourseRepository(CourseRepository courseRepository) {
this.courseRepository = courseRepository;
}
public Boolean getAllTopics() {
ArrayList<Topics> topicList=(ArrayList<Topics>) courseRepository.findAll();
if(topicList.isEmpty())
{
return false;
}
return true;
}
}
Repository class
public interface CourseRepository extends CrudRepository<Topics,Long>{
}
Domain class
#Entity
#Table(name="Book")
public class Topics {
#Id
#Column(name="Topicid")
private long topicId;
#Column(name="Topictitle",nullable=false)
private String topicTitle;
#Column(name="Topicauthor",nullable=false)
private String topicAuthor;
public long getTopicId() {
return topicId;
}
public void setTopicId(long topicId) {
this.topicId = topicId;
}
public String getTopicTitle() {
return topicTitle;
}
public void setTopicTitle(String topicTitle) {
this.topicTitle = topicTitle;
}
public String getTopicAuthor() {
return topicAuthor;
}
public void setTopicAuthor(String topicAuthor) {
this.topicAuthor = topicAuthor;
}
public Topics(long topicId, String topicTitle, String topicAuthor) {
super();
this.topicId = topicId;
this.topicTitle = topicTitle;
this.topicAuthor = topicAuthor;
}
}
Following is the Junit class I have written but courseRepository is getting initialized to NULL and hence I am getting NullPointerException.
public class CourseServiceTest {
#Mock
private CourseRepository courseRepository;
#InjectMocks
private CourseService courseService;
Topics topics;
#Mock
private Iterable<Topics> topicsList;
#Before
public void setUp() {
MockitoAnnotations.initMocks(CourseServiceTest.class);
}
#Test
public void test_Get_Topic_Details() {
List<Topics> topics = new ArrayList<Topics>();
Mockito.when(courseRepository.findAll()).thenReturn(topics);
boolean result=courseService.getAllTopics();
assertTrue(result);
}
}
Change the setUp() method to:
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
Probably you are dealing with some problem on the framework to make the mocked class be injected by the framework.
I recommend to use Constructor Injection, so you don't need to rely on the reflection and #Inject/#Mock annotations to make this work:
#Service
public class CourseService {
private final CourseRepository courseRepository;
// #Autowired annotation is optional when using constructor injection
CourseService (CourseRepository courseRepository) {
this.courseRepository = courseRepository;
}
// .... code
}
The test:
#Test
public void test_Get_Topic_Details() {
List<Topics> topics = new ArrayList<Topics>();
Mockito.when(courseRepository.findAll()).thenReturn(topics);
CourseService courseService = new CourseService(courseRepository);
boolean result = courseService.getAllTopics();
assertTrue(result);
}

Resources