Using a combination of testng and jmockit to do some unit testing. In a method I am testing, it tries to access a system property that I set using a JBoss deploy script, therefore my unit test doesn't have access to the entire JBoss environment to access the properties, so it returns null when testing that method. Tried mocking and setting the system variable directly in my test, but the system property is still returning null in the class that I am testing.
The class being tested:
//returns the correct value in the application but returns null for the test
public static final String webdavrootDir = System.getProperty("property.name");
public String getFileUrl(){
StringBuilder sb = new StringBuilder();
return sb.append(webdavrootDir)
.append(intervalDir)
.append(fileName)
.toString();
}
The test:
#Test
public void getUrl(#Mocked System system){
system.setProperty("property.name", "https://justatest.com/dav/bulk");
String fileUrl = csvConfig.getFileUrl();
assertEquals(fileUrl, "https://justatest.com/dav/bulk/otherstuff");
}
The test finds the value null/otherstuff but expects https://justatest.com/dav/bulk/otherstuff
I have also tried setting the system property in a testng #BeforeMethod method without any success.
Make sure you call System.setProperty("property.name", "https://justatest.com/dav/bulk"); before the class being tested is instantiated, otherwise the static field will always be null.
Consider using a #BeforeClass setup method for this:
#BeforeClass
public static void setup() {
System.setProperty("property.name", "https://justatest.com/dav/bulk");
// Instantiate your CsvConfig instance here if applicable.
}
and then
#Test
public void getUrl(){
System.setProperty("property.name", "https://justatest.com/dav/bulk");
String fileUrl = csvConfig.getFileUrl();
assertEquals(fileUrl, "https://justatest.com/dav/bulk/otherstuff");
}
If you want to use jMocki, but you have to make sure it is done, before your class-under-test is beeing loaded (because of the static field).
#BeforeClass
public static void fakeSystemProperty() {
new MockUp<System>() {
#Mock
public String getProperty(String key) {
return "https://justatest.com/dav/bulk";
}
};
}
Another way would be to modify the class-under-test and partially mock this one, e.g.:
public class CsvConfig {
private static final String webdavrootDir = System.getProperty("property.name");
public static String getProperty() {
return webdavrootDir;
}
}
The test:
#BeforeClass
public static void fakeSystemProperty() {
new MockUp<CsvConfig>() {
#Mock
public String getProperty() {
return "https://justatest.com/dav/bulk";
}
};
}
Related
Below is the method I'm trying to write unit test using junit 5
#Value("${proxy.host}")
private String endpoint;
public Request<Void> setAwsRequestGETParameter(String setStatusPath) {
Request<Void> requestAws = new DefaultRequest<Void>("sts");
requestAws.setHttpMethod(HttpMethodName.GET);
requestAws.setEndpoint(URI.create(endpoint));
requestAws.setResourcePath(setStatusPath);
return requestAws;
}
Below is the unit test I'm trying to run
#InjectMocks
private AWSAuthHandler testAWSAuthHandler;
#Test
public void testSetAwsRequestGETParameter() throws Exception {
URI mockedURI = Mockito.mock(URI.class);
assertNotNull(testAWSAuthHandler.setAwsRequestGETParameter("/status/7deaed5e-3080-45ec-89ba-403977d60c0c"));
}
Below is the stack trace:
java.lang.NullPointerException
at java.base/java.net.URI$Parser.parse(URI.java:3106)
at java.base/java.net.URI.<init>(URI.java:600)
at java.base/java.net.URI.create(URI.java:881)
Can someone please help me with the missing part? Thank you
For setting properties of class that you can't mock you can use Spring Reflection Utils, like that:
ReflectionUtils.setField(field, target, value);
where the field is the name of the field which you want to set ("endpoint" for your case),
target is the mocked class (testAWSAuthHandler for your case)
value is the wanted value
As Sweta Sharma said, you need to initialise AWSAuthHandler with some value for endpoint field. That's why it is better to use constructor injection rather than field one.
Assuming your AWSAuthHandler class look like this (as you didn't provide the code for the whole class):
public class AWSAuthHandler {
#Value("${proxy.host}")
private String endpoint;
public Request<Void> setAwsRequestGETParameter(String setStatusPath) {
Request<Void> requestAws = new DefaultRequest<Void>("sts");
requestAws.setHttpMethod(HttpMethodName.GET);
requestAws.setEndpoint(URI.create(endpoint));
requestAws.setResourcePath(setStatusPath);
return requestAws;
}
You can refactor it in the following way:
public class AWSAuthHandler {
private String endpoint;
public AWSAuthHandler(#Value("${proxy.host}") String endpoint) {
this.endpoint = endpoint;
}
public Request<Void> setAwsRequestGETParameter(String setStatusPath) {
Request<Void> requestAws = new DefaultRequest<Void>("sts");
requestAws.setHttpMethod(HttpMethodName.GET);
requestAws.setEndpoint(URI.create(endpoint));
requestAws.setResourcePath(setStatusPath);
return requestAws;
}
Then you can create tests for this class:
private AWSAuthHandler testAWSAuthHandler;
#BeforeEach
void setUpTests() {
this.testAWSAuthHandler = new AWSAuthHandler("some-endpoint-here");
}
#Test
public void testSetAwsRequestGETParameter() throws Exception {
assertNotNull(testAWSAuthHandler.setAwsRequestGETParameter("/status/7deaed5e-3080-45ec-89ba-403977d60c0c"));
}
You can read more about Spring #Value annotation here, for example: https://www.baeldung.com/spring-value-annotation
I have a class like this
public class LoginPresImpl implements LoginAPIInterface.LoginDataListener, LoginAPIInterface.LoginPresenter{
LoginAPIInterface.LoginView loginView;
LoginAPIInterface.LoginDataInteractor loginDataInteractor;
public LoginPresImpl(LoginAPIInterface.LoginView loginView) {
this.loginView = loginView;
loginDataInteractor=new LoginDataModel(this);
}
#Override
public void getLoginUpdateData(String username, String password,String registrationToken) {
loginDataInteractor.getLoginData(username,password,registrationToken);
}
}
I want to test if calling
getLoginUpdateData()
will call the getLoginDate() method of loginDataInteractor.
I have created a test class like this
public class LoginPresImplTest {
LoginAPIInterface.LoginDataInteractor loginDataInteractorMock;
LoginAPIInterface.LoginView loginViewMock;
LoginPresImpl loginPres;
#Before
public void setUp(){
loginDataInteractorMock = Mockito.mock(LoginAPIInterface.LoginDataInteractor.class);
loginViewMock = Mockito.mock(LoginAPIInterface.LoginView.class);
loginPres = Mockito.spy(LoginPresImpl.class);
}
#Test
public void getLoginUpdateData() {
loginPres.getLoginUpdateData("01","","");
verify(loginPres).getLoginUpdateData("01","","");
}
But I don't know how to check if calling
getLoginUpdateData()
will eventually call
loginDataInteractor.getLoginData()
method. How can I test this using JUnit or Mockito.
I want to test if calling
getLoginUpdateData()
will call the getLoginDate() method of loginDataInteractor.
loginDataInteractor is a dependency of the code under test (cut) you showed.
In a UnitTest you only verify the behavior of the cut. You do not verify the behavior of the dependencies. They get their own unit tests.
I am writing unit test case for a Class
public class CurrentMoreInfoDataProvider implements CurrentMoreInfoInterface.presenterToModel{
private CurrentMoreInfoInterface.modelToPresenter modelToPresenter;
public CurrentMoreInfoDataProvider(CurrentMoreInfoInterface.modelToPresenter modelToPresenter) {
this.modelToPresenter = modelToPresenter;
}
#Override
public void provideData() {
WeatherApiResponsePojo apiWeatherData = WeatherDataSingleton.getInstance().getApiWeatherData();
if(null != apiWeatherData.getCurrently()){
CurrentlyPojo currently = apiWeatherData.getCurrently();
if(null != currently){
populateWeatherData(currently);
}
}
}
public void populateWeatherData(CurrentlyPojo currently) {....}
I want to just use verify method of power mock to test whether populateWeatherData get executed or not. Below is my test case so far.
#RunWith(PowerMockRunner.class)
#PrepareForTest(CurrentMoreInfoDataProvider.class)
public class TestCurrentMoreInfoDataProvider {
private CurrentMoreInfoDataProvider dataProvider;
#Mock
CurrentMoreInfoInterface.modelToPresenter modelToPresenter;
private CurrentlyPojo currentlyPojo = new CurrentlyPojo();
#Test
public void testPopulateWeatherData(){
dataProvider = PowerMockito.spy(new CurrentMoreInfoDataProvider(modelToPresenter));
dataProvider.provideData();
Mockito.verify(dataProvider).populateWeatherData(currentlyPojo);
}
}
If I run this I get null pointer exception in provideData method at
if(null != apiWeatherData.getCurrently()){
How should I provide apiWeatherData to provideData method in that class?
You have to mock WeatherDataSingleton.getInstance().getApiWeatherData() too.
This would be much easier if you would not use static access in general and the Singelton pattern in particular.
I tried mocking it, but how should i provide that mock object to provideData() ?
create a mock of WeatherDataSingleton.
Configure your Test so that this mock is used (by properly using dependency injection or by surrendering to your bad design using Powermock).
configure the mock to return the data:
doReturn(currentlyPojo).when(weatherDataSingletonMock).getApiWeatherData();
This resolves the NPE.
I dont think you need to go for PowerMockito if you apply a simple refactor to your production code:
public class CurrentMoreInfoDataProvider{
#Override
public void provideData() {
WeatherApiResponsePojo apiWeatherData = getApiWeatherData();
if(null != apiWeatherData.getCurrently()){
CurrentlyPojo currently = apiWeatherData.getCurrently();
if(null != currently){
populateWeatherData(currently);
}
}
}
WeatherApiResponsePojo getApiWeatherData(){
return WeatherDataSingleton.getInstance().getApiWeatherData();
}
then in your test expect that new method to return certain object:
#RunWith(MockitoJUnitRunner.class)
public class TestCurrentMoreInfoDataProvider {
private CurrentMoreInfoDataProvider dataProvider;
#Mock
CurrentMoreInfoInterface.modelToPresenter modelToPresenter;
#Mock
WeatherApiResponsePojo apiWeatherDataMock;
private CurrentlyPojo currentlyPojo = new CurrentlyPojo();
#Test
public void testPopulateWeatherData(){
dataProvider = PowerMockito.spy(new CurrentMoreInfoDataProvider(modelToPresenter));
doReturn(apiWeatherDataMock).when(dataProvider).getApiWeatherData();
dataProvider.provideData();
Mockito.verify(dataProvider).populateWeatherData(currentlyPojo);
}
}
Consider the following field and method from a class i need to test.
private final static String pathToUUID = "path/to/my/file.txt";
public String getUuid () throws Exception {
return new String(Files.readAllBytes(Paths.get(pathToUUID)));;
}
The UUID is stored in a file that is created on the application's first run. A file.txt exists in the location indicated by pathToUUID. I am trying (and struggling) to write a unit test for this method.
#RunWith(PowerMockRunner.class)
#PrepareForTest({Files.class})
public class MyTest {
private final String expected = "19dcd640-0da7-4b1a-9048-1575ee9c5e39";
#Test
public void testGetUuid() throws Exception {
UUIDGetter getter = new UUIDGetter();
PowerMockito.mockStatic(Files.class);
when(Files.readAllBytes(any(Path.class)).thenReturn(expected.getBytes());
String retrieved = getter.getUuid();
Assert.assertEquals(expectedUUID, retrieved);
}
}
Unfortunately when().thenReturn() is not called during testing and the test performs as an integration test, reading the file from the file system and returning its value, rather simply than the mock value i expect. However, if i spoof a call to Files.readAllBytes() in the test method and echo the result to the console, the expected value displays.
So, how can i get my method under test to properly function with the PowerMock when()-thenReturn() pattern?
For anyone facing a similar problem, i solved this by making the following changes to my test class:
#RunWith(PowerMockRunner.class)
#PrepareForTest({UUIDStasher.class})
public class TestUUIDStasher {
private final String expectedUUID = "19dcd640-0da7-4b1a-9048-1575ee9c5e39";
Path spoofPath = Paths.get("C:\\DIRECTORY");
#Before
public void setup() throws Exception {
MockitoAnnotations.initMocks(this);
PowerMockito.mockStatic(Paths.class);
PowerMockito.mockStatic(Files.class);
when(Paths.get(any(String.class))).thenReturn(spoofPath);
when(Files.readAllBytes(any(Path.class))).thenReturn(expectedUUID.getBytes());
}
#Test
public void testGetUUID() throws Exception {
UUIDStasher stasher = new UUIDStasher();
String retrieved = stasher.getUuid();
Assert.assertEquals(expectedUUID, retrieved);
}
}
Your class that you need to test is written in a bad way. The path shouldn't be hard coded - make it parametrizable - for example inject the path via the constructor. Then, in your integration tests just inject the path to your test resources and you're ready to go. No PowerMock, no hacks - simple constructor injection.
JDK classes are hard to deal with when using PowerMock. Here's what I would do in your case:
Refactor UUIDGetter to add a constructor for testing purposes that accepts the path to the "uuid" file:
package so37059406;
import java.nio.file.Files;
import java.nio.file.Paths;
public class UUIDGetter {
private final static String PATH_TO_UUID = "path/to/my/file.txt";
private final String path;
public UUIDGetter() {
this(PATH_TO_UUID);
}
// for testing purposes
protected UUIDGetter(final String path) {
this.path = path;
}
public String getUuid() throws Exception {
return new String(Files.readAllBytes(Paths.get(this.path)));
}
}
then test it like this:
package so37059406;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class UUIDGetterTest {
#Test
public void testGetUuid() throws Exception {
final UUIDGetter getter = new UUIDGetter(getClass().getClassLoader().getResource("so37059406/uuid.txt").getPath());
assertEquals("19dcd640-0da7-4b1a-9048-1575ee9c5e39", getter.getUuid());
}
}
With a resource file (in test resources folder) named "so37059406/uuid.txt" and containing (no end-of-line):
19dcd640-0da7-4b1a-9048-1575ee9c5e39
This is IMHO, way better, because:
No powermock: it's a powerful tool but it comes with a price (slower tests, possible tests strange interactions
It's more readable / easy to understand
I'm using Android SDK and junit4 + Mockito for unit testing. Say I have a class like this in my app:
public class Container{
#NonNull private Set<String> values = new HashSet<>();
public void addValue(String value) {
values.add(value);
}
#NonNull
public Set<String> getValues() {
return values;
}
}
And I also have a unit test with Mockito that looks like this:
public class ContainerTest {
private Container container;
#Before
public void before() {
container = mock(Container.class);
}
#Test
public void shouldAddValue() {
container.add("test_value");
assertTrue(container.getValues.contains("test_value"));
}
}
This test actually fails on line "container.add("test_value");" because mock(Container.class) creates a class in which values field is actually set to null, so values.add(value) in addValue() method throws an NPE. I could add a null check in addValue() to fix this, but that seems absurd, since values are already declared non null.
Is there any way to make Mockito respect #NonNull annotations and initialize the field properly?
I think you aren't using Mockito in the right way, since you have to define the Mockito behaviors.
For instance, you should have something like this:
#Test
public void shouldAddValue() {
Set<String> mySet = new HashSet<String>();
mySet.put("test_value");
// Mock container getValues() method to return mySet
when(container.getValues()).thenReturn(mySet); // do import static for Mockito.when
assertTrue(container.getValues().contains("test_value"));
}
Mockito works pretty well when you mock responses, but what you want is to let Mockito to initialize classes for you which clearly it isn't Mockito goals.
Therefore, if you want to test your Container object, then you don't have to mock Container itself and you can have something like this:
public class ContainerTest {
private Container container;
#Before
public void before() {
container = new Container(); // Initialize container
}
#Test
public void shouldAddValue() {
container.addValue("test_value");
assertTrue(container.getValues().contains("test_value"));
}
}