I would like to now, if it is possible to mock a class like
public class MyClass{
...
}
Our business logic create this object with new myClass() somewhere in the code and therefore I don't have access to the created object to mock those methods. Is there a way to replace the whole class or to overwrite those methods. I'm using mockito and I only found examples to do this like
#Test
public void myTest{
MyClass myClass = Mockito.mock(MyClass.class);
Mockito.when(myClass.myMethod()).thenReturn("hello World");
...
}
We can't use PowerMock because it isn't compatible with our test environment.
Any suggestions are welcome.
Sorry, i see only two hardcore solutions:
Make Powermock working by using PowerMockRule and PowerMock Rule Agent:
Getting javassist not found with PowerMock and PowerRule in Junit with Mockito
or
Use Java Reflection to set the mocked object to MyClass: Is it possible in Java to access private fields via reflection
I found a passable way to achieve my requirement.
I converted MyClass to a bean, just add annotation #Dependent.
#Dependent
public class MyClass{
public Integer someMethod(){
return 100;
}
}
I use MyClass in business logic like that
public class BusinessClass{
#Inject
MyClass myClass
public Integer doSomething(){
return myClass.someMethod();
}
}
After this change I'm able to mock the class in my test with annotation #Specializes
#Specializes
#Dependent
public class MyClassMock extends MyClass
{
#Override
public Integer someMethod(){
return 23; // return my mocked value
}
}
MyClass will be automatically replaced with MyClassMock in testenvironment.
Related
I have a Singleton class that I want to test. It uses a #Inject annotation for that class's contructor. Now for testing I want to call a public method for that class in my test class but unable to do so. I have mocked an object that is getting passed to the constructor.
#Inject
private SomeClass(SomeOtherClassObject obj) {
super(obj);
}
I mocked the above private constructor in the following way:
Singleton mockSingleton = PowerMock.createMock(Singleton.class);
PowerMock.expectNew(Singleton.class).andReturn(mockSingleton);
I dont understand how do I call the following method
public SomeClass someMethod(int 1, String 2){
//some logic
return (Object of SomeClass)
}
Any help will be appreciated. Thank You.
If you are using guice as well, you can provide a module in your test that binds SomeOtherClassObject to your mock instance. Then create the SomeClass instance via Guice's injector.
#Test
public void test() {
SomeOtherClassObject other = ...; // what ever you need to create the Mock
Injector injector = Guice.createInjector(new AbstractModule(){
public void configure() {
bind(SomeOtherClassObject.class)toInstance(other);
}
});
SomeClass some = injector.getInstance(SomeClass.class); // guice takes care of the constructor injection
some.someMethod(...);
}
If you dont use guice, have a look at needle4j. Its a test-support lib that automatically injects mocks when injection is required. But it works only with easymock or mockito.
Let's say I have a class (OrchestratingClass) that has a method orchestrate() that calls a number of smaller methods of other classes (classA's do1() method, classB's do2() method). I would like to test the behavior of orchestrate() by mocking the responses of do1() and do2() with various permutations. I'm running my test with something like:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public OrchestratingClassTest {
#Inject
private OrchestratingClass oc;
#Test
public void test1() {
// I would like to mock classA's do1() method to send back "1"
// I would like to mock classB's do2() method to send back "2"
}
#Test
public void test2() {
// I would like to mock classA's do1() method to send back "100"
// I would like to mock classB's do2() method to send back "200"
}
static class SimpleConfig {
#Bean
public InterfaceA interfaceA() {
return new ClassA();
}
#Bean
public InterfaceB interfaceB() {
return new ClassB();
}
#Bean
public OrchestratingClass orchestratingClass() {
return new OrchestratingClass();
}
}
}
And the orchestratingClass itself is quite basic, but I've added some sample code to aid in visualization:
#Named
public OrchestratingClass {
#Inject
private InterfaceA interfaceA;
#Inject
private InterfaceB interfaceB;
public String orchestrate() {
return interfaceA.do1() + " " + interfaceB.do2();
}
}
Now I'm aware I could tweak my SimpleConfig class to have the mocked out versions of classA and classB, but then I'm locked into 1 particular mock and can't "re-mock" things when I move onto test2(). I'm convinced that playing around with the java config files for 1 single test class would not work if we're trying to inject different "flavors" of beans "per-test". Does anyone have any recommendation on what I can do to make sure I'm really testing this thoroughly without being invasive (ex: adding superfluous "setters" for the specific classes in the orchestratingClass to side-step the bean injection pain)? Essentially, I'm looking to "tamper" the applicationContext on a per-test basis for specific beans of interest (along with the necessary housekeeping that's required) by applying a variety of mocks.
Here's a simple example using Mockito:
public class OrchestratingClassTest {
#Mock
private ClassA mockA;
#Mock
private ClassB mockB;
#InjectMocks
private OrchestratingClass oc;
#Before
public void prepare() {
MockitoAnnotations.initMocks(this);
}
#Test
public void shouldConcatenate() {
when(mockA.do1()).thenReturn("1");
when(mockB.do2()).thenReturn("2");
assertEquals("1 2", oc.orchestrate());
}
}
The magic happens in the call to MockitoAnnotations.initMocks(this), which will create mock instances for the fields annotated with #Mock, then create a real instance of Orchestrating class and inject its fields, thanks to #InjectMocks.
Note that, even without this magic, you could make your class easily testable by just adding a constructor taking ClassA and ClassB as arguments to OrchestratingClass, and annotate that constructor with #Autowired instead of annotating the fields. So, in short, use constructor injection rather than field injection.
Let's say you have the following class you would like to test:
public class SomeService {
public String someMethod(SomeEntity someEntity) {
return someEntity.getSomeProperty();
}
}
The SomeEntity looks like this:
public class SomeEntity {
private String someProperty;
public getSomeProperty() {
return this.someProperty;
}
}
The assertion you would like to do can be the following:
String result = someService.someMethod(someEntity);
assertThat(result).isEqualTo("someValue");
How can you make this test work?
1) Add a setter for 'someProperty' in the SomeEntity class. I don't think this a good solution because you don't change production code to make your tests work.
2) Use ReflectionUtils to set the value of this field. Test would look like this:
public class TestClass {
private SomeService someService;
#Test
public void testSomeProperty() {
SomeEntity someEntity = new SomeEntity();
ReflectionTestUtils.setField(someEntity, "someProperty", "someValue");
String result = someService.someMethod(someEntity);
assertThat(result).isEqualTo("someValue");
}
}
3) You create an inner class in your test class that extends the SomeEntity class and adds the setter for this field. However, for this to work you will also need to change the SomeEntity class because the field should become 'protected' instead of 'private'. Test class might look like this:
public class TestClass {
private SomeService someService;
#Test
public void testSomeProperty() {
SomeEntityWithSetters someEntity = new SomeEntityTestWithSetters();
someEntity.setSomeProperty("someValue");
String result = someService.someMethod(someEntity);
assertThat(result).isEqualTo("someValue");
}
public class SomeEntityWithSetters extends SomeEntity {
public setSomeProperty(String someProperty) {
this.someProperty = someProperty;
}
}
}
4) You use Mockito to mock SomeEntity. Seems fine if you only need to mock only one property in the class, but what if you need to mock like 10 properties are so. The test might look like this:
public class TestClass {
private SomeService someService;
#Test
public void testSomeProperty() {
SomeEntity someEntity = mock(SomeEntity.class);
when(someEntity.getSomeProperty()).thenReturn("someValue");
String result = someService.someMethod(someEntity);
assertThat(result).isEqualTo("someValue");
}
}
you can set the value using reflection. It doesn't need any change in production code.
ReflectionTestUtils.setField(YourClass.class, "fieldName", fieldValue);
You can add a setter with default (package private) scope.
With junit testing of SomeService.someMethod()
alternative 1. should not use this as no need to change entity for writing junit.
alternative 2. can be used.
alternative 3. again same a 3, no need to extend for just junit. how about when the class cannot be extended.
alternative 4. yes, a good option. mockito is being used for the same reason.
What is the behavior / contract specific to SomeService that is testable? Based upon your skeletal code, there really isn't any. It will either throw a NPE on bad input, or return a String that may or may not be null, depending on Hibernate magic. Not sure what you can actually test.
I have been through this same dilemma many times before, a quick solution is to make the field you want to mock package protected, or provide a protected setter. Of course both will alter production code.
Alternatively, you can consider dependency injection framework, such as Dagger. Below is an example they give:
#Module
class DripCoffeeModule {
#Provides Heater provideHeater(Executor executor) {
return new CpuHeater(executor);
}
}
This JUnit test overrides DripCoffeeModule's binding for Heater with a mock object from Mockito. The mock gets injected into the CoffeeMaker and also into the test.
public class CoffeeMakerTest {
#Inject CoffeeMaker coffeeMaker;
#Inject Heater heater;
#Before public void setUp() {
ObjectGraph.create(new TestModule()).inject(this);
}
#Module(
includes = DripCoffeeModule.class,
injects = CoffeeMakerTest.class,
overrides = true
)
static class TestModule {
#Provides #Singleton Heater provideHeater() {
return Mockito.mock(Heater.class);
}
}
#Test public void testHeaterIsTurnedOnAndThenOff() {
Mockito.when(heater.isHot()).thenReturn(true);
coffeeMaker.brew();
Mockito.verify(heater, Mockito.times(1)).on();
Mockito.verify(heater, Mockito.times(1)).off();
}
}
I am doing some tests for the class Export
I need to mock a method so I made a mockito (I am new to Mockito)
public Class ExportServiceImpl implements ExportService{
#Autowired
Service service
public void export(){
String exportString = service.getPath();
domoreStuff() ....
}
And
public Class ServiceImpl implements Service(){
public String getPath(){
return "thePath";
}
}
I need to mock the getPath() method so I did in the TestNG
public class ExportTestNG(){
public textExport(){
Service serviceMock = Mockito.mock(Service.class);
Mockito.when(serviceMock.getData()).thenReturn("theNewPath");
System.out.println("serviceMock.getData() : " + serviceMock.getData()); // prints "theNewPath", OK
exportService.export(); // the getData() is not the mockito one
}
}
I may have not correclt mockito and I may not have understood how it works.
Any idea ?
You can use Mockito to inject the mocks for you and avoid having to add setter methods.
#RunWith(MockitoJUnitRunner.class)
public class ExportTestNG(){
#InjectMocks
private ExportServiceImpl exportService;
#Mock
private Service serviceMock;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
public textExport(){
Mockito.when(serviceMock.getData()).thenReturn("theNewPath");
exportService.export();
}
}
You need to wire the mock service into the exportService object.
If you have a setter for the service member variable then do this:
exportService.setService(serviceMock);// add this line.
exportService.export();
If you don't have a setter you will need to perform the wiring before calling export.
Options for this include:
Set the value of the service member variable using reflection.
Write a test-only version of the Service and use a test-only version of the spring configuration xml files.
Something else (that I have never done and thus don't know about).
For a test I like to create a new instance of ComplicatedClass . In reality it's very complicated to crate this instance, but I don't need the real constructor to run nor any of it's data. All I need is an object of ComplicatedClass. How can I do that?
public class ComplicatedClass {
public ComplicatedClass(/* lots of dependencies */) {
}
}
#Test
public class SomeTest {
public void test1() {
ComplicatedClass complicatedInstance = /* new ComplicatedClass(); /*
AnotherClass ac = new AnotherClass(complicatedInstance);
/* ... */
}
}
#Tested annotation does this:
#Tested ComplicatedClass complicatedInstance;
That's it. Please note that the above won't do any mocking. It is just convenient way of creating instances without calling consturctors, etc.
If you want ComplicatedClass to be mocked, use #Mocked annotation:
#Mocked ComplicatedClass complicatedInstance;
In this case, you also get your instance automatically created, but the instance is mocked.
#Tested internally instantiates the class object.
But in case of Junit test case writing of singleton class how #Tested internally creates instance because for singleton private constructor is there.