How to load values from custom properties file for junit testing using Mockito? - junit

I have written this test class to check a service. This is in folder test/java/example/demp/Test.java
#RunWith(MockitoJUnitRunner.class)
#TestPropertySource("classpath:conn.properties")
public class DisplayServiceTest {
#Value("${id}")
private String value;
#Mock
private DisplayRepository DisplayReps;
#InjectMocks
private DisplayService DisplayService;
#Test
public void whenFindAll_thenReturnProductList() {
Menu m = new Menu()
m.setId(value); //when I print value its showing 0
List<Display> expectedDisplay = Arrays.asList(m);
doReturn(expectedDisplay).when(DisplayReps).findAll();
List<Display> actualDisplay = DisplayService.findAll();
assertThat(actualDisplay).isEqualTo(expectedDisplay);
}
My properties file
This is in folder test/resources/conn.properties
id=2
What is the right way to set properties from custom properties file? Cause its not loading values ?

Mockito is a mocking framework, so in general you can't load properties file with Mockito.
Now you've used #TestPropertySource which is a part of Spring Testing and it indeed allows loading properties file (that have nothing to do with mockito though). However using it requires running with SpringRunner and in general its good for integration tests, not for unit tests (Spring Runner among primarily loads Spring's application context).
So if you don't want to use spring here, you should do it "manually". There are many different ways to load Properties file from class path (with getClass().getResourceAsStream() to get the input stream pointing on the resource file and the read it into Properties by using Properties#load(InputStream) for example.
You can also use other thirdparties (not mockito), like apache commons io to read the stream with IOUtils class
If you want to integrate with JUnit 4.x you can even create a rule, described here

#TestPropertySource is a spring annotation, so you need to use the SpringRunner.
You can initialize Mockito using MockitoAnnotations.initMocks(this);, check the example below.
#RunWith(SpringRunner.class)
#TestPropertySource("classpath:conn.properties")
public class DisplayServiceTest {
#Value("${id}")
private String value;
// ...
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
// ...
}

You could use just Mockito and JUnit 4. At the #Before method, call MockitoAnnotations.initMocks and load the properties file:
public class DisplayServiceTest {
private String value;
#Mock
private DisplayRepository displayReps;
#InjectMocks
private DisplayService displayService;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
Properties prop = loadPropertiesFromFile("conn.properties");
this.value = prop.getProperty("id");
}
private Properties loadPropertiesFromFile(String fileName) {
Properties prop = new Properties();
try {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
InputStream stream = loader.getResourceAsStream(fileName);
prop.load(stream);
stream.close();
} catch (Exception e) {
String msg = String.format("Failed to load file '%s' - %s - %s", fileName, e.getClass().getName(),
e.getMessage());
Assert.fail(msg);
}
return prop;
}
#Test
public void whenFindAll_thenReturnProductList() {
System.out.println("value: " + this.value);
Menu m = new Menu();
m.setId(this.value); // when I print value its showing 0
List<Display> expectedDisplay = Arrays.asList(m);
Mockito.doReturn(expectedDisplay).when(this.displayReps).findAll();
List<Display> actualDisplay = this.displayService.findAll();
Assert.assertEquals(expectedDisplay, actualDisplay);
}
}

Related

How to use these #DataMongoTest and #SpringBootTest together in integration test

I am trying to write integration test case for one of my rest application which uses mongodb internally to persist the data
#DataMongoTest
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class MainControllerTest {
#LocalServerPort
private int port = 8080;
/* some test cases*/
}
but I am getting below error
java.lang.IllegalStateException: Configuration error: found multiple declarations of #BootstrapWith for test class [com.sample.core.controller.MainControllerTest]: [#org.springframework.test.context.BootstrapWith(value=class org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTestContextBootstrapper), #org.springframework.test.context.BootstrapWith(value=class org.springframework.boot.test.context.SpringBootTestContextBootstrapper)]
looks like these two are mutually exclusive, so how to do the integration testing .
Use #AutoConfigureDataMongo with #SpringBootTest and this will resolve this ambiguity issue. #SpringBootTest and #DataMongoTest cannot be used together.
Answering to a very old post hoping it may help others.
#AutoConfigureDataMongo will connect to real database. In order to still use the embedded mongo, one can initiate the embedded mongoDb manually.
#SpringBootTest(classes = SubscriptionEventApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class SubscriptionEventApiIntegrationTest {
#BeforeAll
static void setup() throws Exception {
startEmbeddedMongoDbManually();
}
private static void startEmbeddedMongoDbManually() throws IOException {
final String connectionString = "mongodb://%s:%d";
final String ip = "localhost";
final int port = 27017;
ImmutableMongodConfig mongodConfig = MongodConfig
.builder()
.version(Version.V3_5_5)
.net(new Net(ip, port, Network.localhostIsIPv6()))
.build();
MongodStarter starter = MongodStarter.getDefaultInstance();
mongodExecutable = starter.prepare(mongodConfig);
mongodExecutable.start();
mongoTemplate = new MongoTemplate(MongoClients.create(String.format(connectionString, ip, port)), "test");
}
#AfterAll
static void clean() {
mongodExecutable.stop();
}
#Test
public void test() {
.....
}
}
Purushothaman suggested starting embedded MongoDB server manually. I am suggesting to start it automatically using #DataMongoTest, but creating WebTestClient manually instead.
Kotlin code below, translates to Java trivially:
#DataMongoTest
// #ContextConfiguration may not be needed for your case.
#ContextConfiguration(
classes = [
Application::class,
MainController::class,
// Add more needed classes for your tests here.
// ...
]
)
#TestPropertySource(properties = ["spring.mongodb.embedded.version=4.0.12"])
class MainControllerTest(
#Autowired
private val mainController: MainController,
// Add more beans needed for your tests here.
// ...
) {
// Creating a WebTestClient is easy and
// can be done in different ways.
// Here is one of the possible ways.
private val webTestClient: WebTestClient =
WebTestClient.bindToController(mainController).build()
#Test
fun someTest() {
// ...
}
}

Mocking AEM Asset Manager using WCM IO

I am creating a sling model which fetched a excel file from the file to read and display data in an AEM component.
#Model(
adaptables = SlingHttpServletRequest.class,
defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL
)
public class OnlineCoursesModel {
#Self
private SlingHttpServletRequest request;
#ValueMapValue
private String filePath;
private List<OnlineCourseDTO> onlineCourses;
#PostConstruct
public void init() {
AssetManager assetManager = request.getResourceResolver().adaptTo(AssetManager.class);
Asset asset = assetManager.getAsset(filePath);
/** Do Something With the Asset **/
}
}
In AEM it's working fine, but when I try to use it with the WCM.io AEM mocking framework, the assetManager is returning null.
#Test
public void checkIfFileIsRead() {
context.load().binaryFile(COURSES_EXCEL_FILE, EXCEL_RESOURCE_PATH);
context.load().json(ONLINE_COURSE_LISTING_AUTHORED, TEST_CONTENT_ROOT);
resource = context.request();
undertest = resource.adaptTo(OnlineCoursesModel.class);
System.out.println(undertest);
}
Your test is a little bit too complicated. Can you please try this simpler version:
#Test
public void checkIfFileIsRead() {
context.create().asset("/content/dam/image.jpg", 1, 1, StandardImageHandler.JPEG_MIMETYPE);
undertest = context.request().adaptTo(OnlineCoursesModel.class);
assertNotNull(undertest);
}
This will create a new asset at /content/dam/image.jpg with a width of 1 and a height of 1 and mime type image/jpg.
You do not need to load a binary and additional json.
Additional notes
You also do not need to adapt from a request. That is considered bad practice and should only be done if you need specific information that is only part of the request. For example information about the user sending the request.
Otherwise, always adapt from Resource.class.
Example:
#Model(adaptables = Resource.class)
public class OnlineCoursesModel {
#OSGiService
private AssetManager assetManager;
#PostConstruct
public void init() {
Asset asset = assetManager.getAsset(filePath);
/** Do Something With the Asset **/
}
}

Camel Properties Load

I just read a post discussing loading properties in a Junit
( Loading Properties File In JUnit #BeforeClass )
The properties load seems to work but I am not sure how to reference the specific property in my unit test ...any ideas - I am trying to load the value of the testinput entry in my properties file ?
============================================================
Property file users.properties content :
testinput=D/somefolder/somefile
public class OrderRouterTest2 extends CamelSpringTestSupport {
#Override
protected AbstractXmlApplicationContext createApplicationContext() {
return new ClassPathXmlApplicationContext("META-INF/spring/camel- context.xml");
}
#BeforeClass
public static void setUpBeforeClass() throws Exception {
final Properties props = new Properties();
final InputStream fileIn = OrderRouterTest2.class.getResourceAsStream("/**users.properties**");
**props.load(fileIn)**;
}
#Test
public void testSendToWebService() throws Exception {
// These don't work
String value1 = context.resolvePropertyPlaceholders("{{testinput}}");
String value2 = "I see ${testinput}";
String value3 = "I see {{testinput}}";
}
You should use useOverridePropertiesWithPropertiesComponent from CamelTestSupport, see: https://camel.apache.org/camel-test.html
Ok ...I tried the obvious ...defining the Property object outside of the before class and that worked ...seems like there must another way though to reference that properties object that was loaded in the before class.

JUnit testing of Ratpack server with Guice injection

I am trying to write a JUnit test with service dependencies being injected.
protected MainClassApplicationUnderTest aut = new MainClassApplicationUnderTest(App.class) {
#Override
protected void addImpositions(final ImpositionsSpec impositions) {
impositions.add(UserRegistryImposition.of(appRegistry -> {
// Allow modifying Injector in tests
return appRegistry.join(Guice.registry(injector));
}));
}
};
private Injector injector = com.google.inject.Guice.createInjector(new Module());
#Before
public void setup () {
injector.injectMembers(this);
}
#After
public void tearDown() {
aut.close();
}
and then using injected services in my test classes:
#Inject
private UserService userService;
This was working fine until I started adding persistence to my app with HikariModule. Now Guice registry creation is a bit more complex:
.join(Guice.registry(b -> b
.module(HikariModule.class, hikariConfig -> {
final String dbUrl = System.getenv("JDBC_DATABASE_URL");
hikariConfig.setJdbcUrl(dbUrl);
})
.module(Module.class)
.bind(DbMigrator.class)
).apply(r))
Because my registry now consists of multiple modules if I have a service that depends on DataSource class coming from HikariModule guice injection fails in tests.
My goal is to allow writing tests in the following fashion:
#Inject // <- not required can be done in #Before method
private UserService userService; // <- Inject it somehow from Application under test
#Test
public void testUser() {
final Result<User, String> userResult = userService.create(new User.Registration());
final ReceivedResponse res = aut.getHttpClient().get("/users/" + user.userId);
assertEquals(200, res.getStatusCode());
}
What is the right approach of injecting service dependencies in tests? I would very much prefer reusing guice modules from MainClassApplicationUnderTest rather than creating my own and overriding them.
After quite some time battling with this issue and help from Ratpack slack I managed to pull this off.
First of all we need to capture our application registry in the local variable.
private Registry appRegistry;
protected MainClassApplicationUnderTest aut = new MainClassApplicationUnderTest(App.class) {
#Override
protected void addImpositions(final ImpositionsSpec impositions) {
impositions.add(UserRegistryImposition.of(r -> {
appRegistry = r;
return Registry.empty();
}));
}
};
It turns out there is a nifty method that starts the application. So when injecting the class we will know that Registry will not be null and we can inject classes.
protected <T> T inject(final Class<T> classOf) {
aut.getAddress();
return appRegistry.get(classOf);
}
Then in test classes we can simply inject any class that is present in the registry.
final UserService userService = inject(UserService.class);
// OR
final DataSource dataSource = inject(DataSource.class);

Can any one help me in mocking a static method which returns an object, and this static method is present in a final class

I need help for below thing,
I have to write a Junit using PowerMock/Mockito for a method which makes a call to a static method of a final class present in an external jar.
The method for which i need to write the JUnit test is:
public class SomeClass {
private PrivateKey privateKeyFromPkcs8(String privateKeyPem) throws IOException {
Reader reader = new StringReader(privateKeyPem);
Section section = PemReader.readFirstSectionAndClose(reader, "PRIVATE KEY");
if (section == null) {
throw new IOException("Invalid PKCS8 data.");
}
byte[] bytes = section.getBase64DecodedBytes();
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes);
try {
KeyFactory keyFactory = SecurityUtils.getRsaKeyFactory();
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
return privateKey;
} catch (NoSuchAlgorithmException exception) {
} catch (InvalidKeySpecException exception) {
}
throw new IOException("Unexpected exception reading PKCS data");
}
}
In the above code PemReader is a final class and readFirstSectionAndClose(reader, "PRIVATE KEY") is a static method in PemReader.
I have tried writing the test shown below but Section object(section) is showing as null while debugging. Perhaps the actual code (PemReader.readFirstSectionAndClose(reader, "PRIVATE KEY")) is getting called instead of the mock.
#RunWith(PowerMockRunner.class)
#PrepareForTest({SomeClass.class,PemReader.class})
public class SomeClassTest {
#InjectMocks
SomeClass mockSomeClass;
#Mock
private Reader mockReader;
#Mock
private Section mockSection;
#Test
public void testPrivateKeyFromPkcs8() throws Exception {
PowerMockito.mockStatic(PemReader.class);
Mockito.when(PemReader.readFirstSectionAndClose(mockReader, "PRIVATE KEY")).thenReturn(mockSection);
assertNotNull(mockSomeClass.privateKeyFromPkcs8(dummyPrivateKey));
}
}
Please help me in writing a Junit using powermockito/mockito
You have to prepare the final, static class.
Here's an example using the PowerMock annotations for JUnit:
#RunWith(PowerMockRunner.class)
#PrepareForTest({PemReader.class})
public class PemReaderTest {
#Mock
private Reader mockReader;
#Mock
private Section mockSection;
#Test
public void testMockingStatic() {
PowerMockito.mockStatic(PemReader.class);
Mockito.when(PemReader.readFirstSectionAndClose(mockReader, "PRIVATE KEY")).thenReturn(mockSection);
Assert.assertEquals(mockSection, PemReader.readFirstSectionAndClose(mockReader, "PRIVATE KEY"));
}
}
For completeness, here's the definition of PemReader:
public final class PemReader {
public static Section readFirstSectionAndClose(Reader reader, String key) {
return null;
}
}
The above test passes with the following versions:
JUnit: 4.12
Mockito: 2.7.19
PowerMock: 1.7.0
Update 1: based on your updated question. Your test case will pass (or at least the invocation on PemReader.readFirstSectionAndClose will return something) if you just make this change:
Mockito.when(PemReader.readFirstSectionAndClose(
Mockito.any(Reader.class),
Mockito.eq("PRIVATE KEY"))
).thenReturn(mockSection);
The version of this instruction in your current test case relies on equality matching between the StringReader which your code passes into readFirstSectionAndClose and the mocked Reader which your test case supplies. These are not 'equal' hence the mocked invocation's expectations are not met and your mockSection is not returned.
A few, unrelated, notes:
There is no need to include SomeClass.class in #PrepareForTest, you only need to include the classes which you want to mock in that annotation, since SomeClass is the class you are trying to test there is no mocking required for that class.
Using #InjectMocks to instance SomeClass is a bit odd, since SomeClass has no (mockito provided) mocks to inject into it :) you can replace this declaration with SomeClass someClass = new SomeClass();
In the code you supplied SomeClass.privateKeyFromPkcs8 has private scope so it cannot be tested (or called in any way) from SomeClassTest.