I have a java class - very typical of the usual singleton - like this :
PLEASE NOTE : I have left out the "if null" logic here, for the sake of brevity, because that isn't what I am having trouble with, and I don't want to crowd the question.
public class MySingleton
{
ObjectMapper mapper;
private MySingleton()
{
new MySingleton(new ObjectMapper())
}
private MySingleton(ObjectMapper mapper)
{
this.mapper = mapper;
}
private static final class Lazy
{
static final MySingleton INSTANCE = new MySingleton();
}
public static MySingleton getInstance()
{
return Lazy.INSTANCE;
}
}
Now - that is great - and that works - but what if I am trying to test this in a unit test...
I want to mock the mapper - so I can do :
ObjectMapper mockObjectMapper = mock(ObjectMapper.class)
But, then when I need to somehow call the constructor of "MySingleton" in order to test it...
How do I do that - given that from my test class, I know it will say "MySingleton(arguments here) has private access in MySingleton"?
Singletons are the enemies of testable code. The links given in the answer to that question are an excellent argumentation on what's evil with singletons as well as why and how to avoid them.
You can use PowerMock to inject your test ObjectMapper instance using ConstructorMocking.
http://benkiefer.com/blog/2013/04/23/powermockito-constructor-mocking/
I had to modify your example singleton so that the constructors were chained correctly.
public class MySingleton {
ObjectMapper mapper;
private MySingleton()
{
//This does not work.
//new MySingleton(new ObjectMapper());
this(new ObjectMapper());
}
private MySingleton(ObjectMapper mapper)
{
this.mapper = mapper;
}
private static final class Lazy
{
static final MySingleton INSTANCE = new MySingleton();
}
public static MySingleton getInstance()
{
return Lazy.INSTANCE;
}
}
I also stubbed the ObjectMapper Class.
public class ObjectMapper {
//Empty Sample uses default CTR
}
I was able to test this as follows using the instructions from the link previously listed:
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PrepareForTest(MySingleton.class)
public class MySingletonTest {
#Test
public void testSingletonCtr() throws Exception {
ObjectMapper mapper = new ObjectMapper();
PowerMockito.whenNew(ObjectMapper.class).withNoArguments().thenReturn(mapper);
Assert.assertEquals(MySingleton.getInstance().mapper, mapper);
}
}
I am doing this in a maven project. I needed the following dependencies added to my test scope:
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-core</artifactId>
<version>1.6.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4-rule</artifactId>
<version>1.6.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>1.6.5</version>
<scope>test</scope>
</dependency>
I do tend to agree that Singletons tend to cause problems long-term for code maintenance and scalability. If you have capacity to look for alternative approaches to your problem it may benefit you to do so. If not, then I believe that the PowerMock utility will provide you the capability you're looking for.
Best of Luck.
Related
I was trying to follow multiple tutorials about the subject but I cannot understand how they support DI. To my basic understanding, DI should be supported by supplying extended/implemented classes object to the test, so the test will be able to be executed with multiple variations of the objects.
For example:
#Test
public void myTest(Base baseObj){
assertThis(baseObj);
assertThat(baseObj);
}
class Base {
//data
//methods
}
class Class1 extends Base{}
class Class2 extends Base{}
class Class3 extends Base{}
There should be a way to supply objects of the derived classes to the test. Am I wrong till here?
I couldn't understand from the explanations, how TestInfo class for example (or the other classes) helps me with that?
Can you enlighten me please?
You can do it like this:
public class Test1 {
#ParameterizedTest
#MethodSource("myTest_Arguments")
public void myTest(Base baseObj){
System.out.println(baseObj);
}
static Stream<Arguments> myTest_Arguments() {
return Stream.of(
Arguments.of(new Class1()),
Arguments.of(new Class2()),
Arguments.of(new Class3()));
}
}
The entire code is:
package com.example.demo;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.stream.Stream;
class Base {}
class Class1 extends Base{}
class Class2 extends Base{}
class Class3 extends Base{}
public class Test1 {
#ParameterizedTest
#MethodSource("myTest_Arguments")
public void myTest(Base baseObj){
System.out.println(baseObj);
}
static Stream<Arguments> myTest_Arguments() {
return Stream.of(Arguments.of(new Class1()),Arguments.of(new Class2()),Arguments.of(new Class3()));
}
}
and the dependencies used are:
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.9.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.9.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.9.0</version>
<scope>test</scope>
</dependency>
I'm running a basic Spring App with Mockito 3.1.0 and and Junit 5.5.2. I have a Service call that includes two Spring Data JPA repositories. These are passed into the constructor for DI (along with two others that are immaterial – I'm including them in case they could also, potentially, cause errors.) I see no issues with the service when the app runs.
When I run my test, I get a NPE for myService. Stepping through the stack trace, hasn't really shown me anything that relates to the error. I have also tried (following this Article: https://www.baeldung.com/mockito-junit-5-extension) updating my test class to look like this:
#ExtendWith(MockitoExtension.class)
#RunWith(JUnitPlatform.class) // This dependency doesn't seem to exist
public class MyServiceTest {
// ...
#BeforeEach
// not the JUnit4 #Before annotation.
// Interestingly, this gives me NPEs for the repositories, not the service.
public void setup(){
// ...
}
}
to no avail. What I suspect is happening is that something about my setup isn't properly wired up – either as dependencies or syntax for DI.
How do I debug this? What am I missing? Thanks in advance!
Service:
import org.springframework.stereotype.Service;
#Service
public class MyService {
private final Repository1 repository1;
private final Repository2 repository2;
private final Repository3 repository3;
private final Repository4 repository4;
public MyService(Repository1 repository1,
Repository2 repository2,
Repository3 repository3,
Repository4 repository4) {
this.repository1 = repository1;
this.repository2 = repository2;
this.repository3 = repository3;
this.repository4 = repository4;
}
public Boolean computeValue(String someInput) {
// does computations with repository1, repository2.
}
}
Test:
import static org.mockito.Mockito.when;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
#RunWith(MockitoJUnitRunner.class)
public class MyServiceTest {
#Mock
private Repository1 repository1;
#Mock
private Repository2 repository2;
#Mock
private Repository3 repository3;
#Mock
private Repository4 repository4;
#InjectMocks
private MyService myService;
#Before
public void setup {
when(repository1.findAll()).thenReturn(new ArrayList<>());
when(repository1.findAllByInput(anyString())).thenReturn(new ArrayList<>());
// Yes; I'm aware that this could also be a call to
// MockitoAnnotations.initMocks(this). I've tried it:
// it doesn't work. Also, I've intentionally not taken this
// approach due to reasons:
// - https://stackoverflow.com/questions/10806345/runwithmockitojunitrunner-class-vs-mockitoannotations-initmocksthis
}
#Test
void callMyService() {
assertTrue(myService.computeValue("123"));
}
}
Sample Repository:
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
// This is just an example, but this pattern is repeated against all
// repositories in the project.
#Repository
public interface Repository1 extends JpaRepository<Repository1, String> {
}
Edit:
I forgot to mention that I have other files in this project that are using exactly these annotations (#RunWith(MockitoJUnitRunner.class), #Mock, #InjectMocks, #Before) that are not failing.
I updated the files with the relevant imports, and added an example of RepositoryN.
I update the MyService class to better reflect the parameters.
For anybody else who encounters this in the future, we were able to fix this problem by changing one of the imports from:
import org.junit.jupiter.api.Test;
to
import org.junit.Test;
Edit:
This had to do with differing versions of JUnit. There's a good long-form explanation as to why here.
Seems like your object myService, is not instantiated. I would suggest not use #InjectMocks and directly create your object as your repositories are already instantiated.
MyService myService = new MyService(..., ..., ...)
I suppose you have to annotate your test class with #ExtendWith(SpringExtension.class) and not with MockitoExtension.class
More info here Junit 5 with Spring Boot: When to use #ExtendWith Spring or Mockito?
I am trying to write unit tests for Quarkus using Mockito, but I fail mocking things.
Here is a minimal (not) working example :
package com.my.package;
import io.quarkus.test.junit.QuarkusTest;
import org.mockito.Mockito;
import org.mockito.Mock;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
#QuarkusTest
public class LoadCalculatorServiceTest {
public class Foobar {
public int baz;
public void setBaz(int baz) {
this.baz = baz;
}
public int getBaz() {
return this.baz;
}
}
#Mock
Foobar foobar;
// Foobar foobar = new Foobar(); // doesn’t work either
#Test
public void myTest() {
Mockito.when(foobar.getBaz()).thenReturn(4); // NullPointer
Assertions.assertEquals(4,foobar.getBaz());
}
}
The test crashes on a NullPointer.
I read such issues may be fixed by annotating the test with #RunWith(MockitoJUnitRunner.class), #ExtendWith(MockitoExtension.class) (which for some reason I expected #QuarkusTest to do anyway ?), however I fail to find the correct imports to load them.
I tried org.junit.jupiter.api.MockitoExtension, org.junit.runner.RunWith and variations, without success.
Here is the relevant part of my pom.xml :
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5-mockito</artifactId>
<scope>test</scope>
</dependency>
What am I missing ?
I figured the original code works with plain-style mocks :
Foobar foobar = Mockito.mock(Foobar.class);
So the question is actually how to make the #Mock annotation work ? There are several things needed for that :
The #RunWith annotation has been replaced (or should we say upgraded) by #ExtendWith in JUnit5. It can be imported in Quarkus using import org.junit.jupiter.api.extension.ExtendWith;.
#RunWith is usually used as #ExtendWith(MockitoExtension.class). MockitoExtension can be imported in Quarkus using import org.mockito.junit.jupiter.MockitoExtension;. Beware that the mockito-junit-jupiter dependency (from the org.mockito group) must be added to the pom.xml, since the quarkus-junit5-mockito packages do not depend on it.
Mocks have to be initialized by MockitoAnnotations.initMocks() before the tests. Note that although it may seem to make more sense to use #BeforeAll for the setup function, apparently it is not the point of this annotation and one should use #BeforeEach (the former needs the setup to be static, and IIUC the setup function will be called before each test anyway).
Then finally the #Mock annotation should work.
To summarize, the original code would become :
package com.my.package;
import io.quarkus.test.junit.QuarkusTest;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
#QuarkusTest
#ExtendWith(MockitoExtension.class)
public class LoadCalculatorServiceTest {
public class Foobar {
public int baz;
public void setBaz(int baz) {
this.baz = baz;
}
public int getBaz() {
return this.baz;
}
}
#BeforeEach
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Mock
Foobar foobar;
#Test
public void myTest() {
Mockito.when(foobar.getBaz()).thenReturn(4);
Assertions.assertEquals(4,foobar.getBaz());
}
}
with the following addition to the pom.xml :
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
I'm using quarkus 1.8.1.Final, with mockito 3.6.0, I had the same issue with #Mock annotation and I followed the answer from Skippy le Grand Gourou and it didn't work, so I deleted the #QuarkusTest annotation, and delete de MockitoAnnotations.initMocks(this) method, my mockito version has deprecated this, then the test run with the #Mock annotation. I'm new doing Quarkus so I don't know very well the side effects of removing #QuarkusTest
The requirement is the same as the question posted here Injecting array of values from properties file in spring boot i.e. consuming a list of related properties defined in an application.properties file.
The thing is, my code uses Core Spring. How can I achieve the same without having to bring in Spring Boot in order to use #ConfigurationProperties ? Using a comma separated list of values won't work in the long term because i wish to express a list of config objects, not just a list of strings
Thanks
You can look at using Apache Commons Configuration which provides rich set of methods to work with properties.
If you want to stick to property files, you can look at using this page for list and arrays:-
List<Object> colorList = config.getList("colors.pie");
Or you can use XML based hierarchical configurations and use things like:-
List<HierarchicalConfiguration<ImmutableNode>> fields = config.configurationsAt("tables.table(0).fields.field");
and
List<Object> fieldNames = config.getList("tables.table(0).fields.field.name");
Read their user-guide, you should find what you are looking for.
If you can add the spring-boot jar as a dependency you can use #ConfigurationProperties with core spring.
package com.stackoverflow.q54119803;
import static java.util.stream.Collectors.*;
import static org.junit.Assert.*;
import java.util.List;
import java.util.stream.Stream;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.io.ClassPathResource;
import org.springframework.test.context.junit4.rules.SpringClassRule;
import org.springframework.test.context.junit4.rules.SpringMethodRule;
#SuppressWarnings("javadoc")
public class So54119803 {
/** The Constant SPRING_CLASS_RULE. */
#ClassRule
public static final SpringClassRule SPRING_CLASS_RULE = new SpringClassRule();
final String anotherPropValue = "anotherPropValue";
final List<String> expected = Stream.of("string1", this.anotherPropValue)
.collect(toList());
/** The spring method rule. */
#Rule
public final SpringMethodRule springMethodRule = new SpringMethodRule();
#Autowired
Props props;
#Test
public void test() {
System.out.println(this.props);
assertEquals(this.anotherPropValue, this.props.getAnotherProp());
assertEquals(String.class, this.props.getClazz());
assertEquals(this.expected, this.props.getStrings());
}
#Configuration
#EnableConfigurationProperties
static class Config {
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
final ClassPathResource location = new ClassPathResource("props.properties");
final PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
propertySourcesPlaceholderConfigurer.setLocation(location);
return propertySourcesPlaceholderConfigurer;
}
#Bean
#ConfigurationProperties("test")
Props props() {
return new Props();
}
}
static class Props {
String anotherProp;
List<String> strings;
Class<?> clazz;
public String getAnotherProp() {
return this.anotherProp;
}
public void setAnotherProp(String anotherProp) {
this.anotherProp = anotherProp;
}
public List<String> getStrings() {
return this.strings;
}
public void setStrings(List<String> strings) {
this.strings = strings;
}
public Class<?> getClazz() {
return this.clazz;
}
public void setClazz(Class<?> clazz) {
this.clazz = clazz;
}
#Override
public String toString() {
return "Props [anotherProp=" + this.anotherProp + ", strings=" + this.strings + ", clazz=" + this.clazz
+ "]";
}
}
}
Sample props file: props.properties
#Conversions and references work fine
test.anotherProp=anotherPropValue
test.strings=string1,${test.anotherProp}
test.clazz=java.lang.String
Dependencies in example:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>
I am using JMock to test the following method in a ProcessingTest class:
public void handle(Process process) {
processor.handleProcess(process);
}
I have mocked out the processor and process classes. For my test for this particular method, my JMock expectations are as follows:
checking( new Expectations() {
{
oneOf( ProcessingTest.this.processor ).handleProcess(
ProcessingTest.this.process );
}
} );
This is causing the following error:
unexpected invocation ...
no expectations specified
....
I assume that there is something incorrect in the expectations, what should they be?
I have tried to expect that the method in invoked atLeast one time, but this seems to be an issue for void methods.
I have no idea where is your problem exactly as you have not provided enough code. This is how to do this with JMock:
import org.jmock.Expectations;
import org.jmock.integration.junit4.JUnitRuleMockery;
import org.jmock.lib.legacy.ClassImposteriser;
import org.junit.Rule;
import org.junit.Test;
public class ProcessingTest {
#Rule
public final JUnitRuleMockery mockery = new JUnitRuleMockery() {{
setImposteriser(ClassImposteriser.INSTANCE);
}};
// just some dummy object, we will be comparing reference only
private final Process process = mockery.mock(Process.class);
private final Processor processor = mockery.mock(Processor.class);
private final Processing processing = new Processing(processor);
#Test
public void test() {
mockery.checking(new Expectations() {{
oneOf(ProcessingTest.this.processor).handleProcess(ProcessingTest.this.process);
}});
processing.handle(process);
}
}
public class Processing {
private final Processor processor;
public Processing(Processor processor) {
this.processor = processor;
}
public void handle(Process process) {
processor.handleProcess(process);
}
}
public interface Processor {
void handleProcess(Process process);
}
You need these dependencies:
<dependency>
<groupId>org.jmock</groupId>
<artifactId>jmock</artifactId>
<version>2.6.0</version>
</dependency>
<dependency>
<groupId>org.jmock</groupId>
<artifactId>jmock-legacy</artifactId>
<version>2.6.0</version>
</dependency>
<dependency>
<groupId>org.jmock</groupId>
<artifactId>jmock-junit4</artifactId>
<version>2.6.0</version>
</dependency>