Mock a Constructor with Parameter

Mock a constructor with parameter

The code you posted works for me with the latest version of Mockito and Powermockito. Maybe you haven't prepared A?
Try this:

A.java

public class A {
private final String test;

public A(String test) {
this.test = test;
}

public String check() {
return "checked " + this.test;
}
}

MockA.java

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest(A.class)
public class MockA {
@Test
public void test_not_mocked() throws Throwable {
assertThat(new A("random string").check(), equalTo("checked random string"));
}
@Test
public void test_mocked() throws Throwable {
A a = mock(A.class);
when(a.check()).thenReturn("test");
PowerMockito.whenNew(A.class).withArguments(Mockito.anyString()).thenReturn(a);
assertThat(new A("random string").check(), equalTo("test"));
}
}

Both tests should pass with mockito 1.9.0, powermockito 1.4.12 and junit 4.8.2

Mocking objects from a constructor parameter

I think your example is not a good practice. Unit testing should be as small as possible. The goal of unit testing is to isolate each part of the program and show that the individual parts are correct.

Anyway, you still can try this approach. I hope it helps.

public class Service {

private ServiceHelper helper;

public Service(ServiceHelper helper) {
this.helper = helper;
}
}

public class ServiceHelper {

private Foo foo;
private Bar bar;

// for unit testing only
ServiceHelper(Foo foo, Bar bar) {
this.foo = foo;
this.bar = bar;
}
}

And the test class :

public class ServiceTest {

@Test
public void your_test() {
// arrange
Foo mockedFoo = mock(Foo.class);
Bar mockedBar = mock(Bar.class);
ServiceHelper helper = new ServiceHelper(mockedFoo, mockedBar); // the 'live' class
Service service = new Service(helper);

// act
service.doSomething();

// your assert ...
}
}

Mocking objects with Moq when constructor has parameters

The last line is giving you a real instance because you are using the new keyword, not mocking CustomerSyncEngine.

You should use Mock.Of<CustomerSyncEngine>()

The only problem with Mocking Concrete types is that Moq would need a public default constructor(with no parameters) OR you need to create the Moq with constructor arg specification. http://www.mockobjects.com/2007/04/test-smell-mocking-concrete-classes.html

The best thing to do would be right click on your class and choose Extract interface.

How to mock a class that has parameters in the constructor using Mock.Of syntax?

Mocking with Moq need the class to be mocked to have methods to be virtual or you can mock any interface. When you are mocking with moq, it will create a dynamic implementation on the fly and thus it does not depend on your implementation. In your case you can just do

public class MyClass
{
public MyClass(IDependency1 dep1, IDependency2 dep2, IDependency3 dep3)
{}

public ReturnType MyNewMethod(Tyep1 t1, Type2 t2)
{
//1. call to ExistingMethod1(); --> I'll just setup the return value
//2. call to ExistingMethod2(); --> I'll just setup the return value
//3. call using the DbContext --> ???
//4. call using the Logger --> ???
}
}

Mock<MyClass> mockedObj = new Mock<MyClass>();

mockedObj.SetUp(x=>x.MyNewMethod()).Returns(objectOfReturnType);

Here you need to make MyNewMethod virtual. The return objectOfReturnType is an object you created as test object. so your method body detail is not required or needed. That is the idea of mocking, you are mocking your actual implementation with fake implementation ( which is the setup in this case). You can vary different return objects depending how you will test the class under test. I recommend you first to read unit testing 101.

Note that you are setting up how MyNewMethod behave. Your implementation might be doing lots of stuff but here what you care is its return. That is why the method also has to be virtual, it will be overriden by the Moq and return what you just setup. Internally that method might call different things...so you don't care

Also you should read the basic of Moq, you can find it here https://github.com/Moq/moq4/wiki/Quickstart

Unit testing with mockito for constructors

Once again the problem with unit-testing comes from manually creating objects using new operator. Consider passing already created Second instead:

class First {

private Second second;

public First(int num, Second second) {
this.second = second;
this.num = num;
}

// some other methods...
}

I know this might mean major rewrite of your API, but there is no other way. Also this class doesn't have any sense:

Mockito.when(new Second(any(String.class).thenReturn(null)));

First of all Mockito can only mock methods, not constructors. Secondly, even if you could mock constructor, you are mocking constructor of just created object and never really doing anything with that object.

How do you use scalamock to mock a class with constructor parameters

I couldn't find the test class on github however the answer to this depends on what you want to achieve. You wouldn't mock a class however using specs2 and mockito you can spy on it to determine if something has happened this is an example of what you might be trying to achieve.

class Responsebuilder(param1: Int, param2: int) {
def doSomething() { doSomethingElse() }
def doSomethingElse() { ...
}

class ResponseBuilderSpec extends Specification with Mockito {
"response builder" should {
"respond" in {
val testClass = spy(new ResponseBuilder(1, 3))
testClass.doSomething()

there was one(testClass).doSomethingElse()
}
}
}

One would normally mock traits as dependencies and then inject them into the test class once you defined their behaviour

trait ResponseBuilderConfig { def configurationValue: String }

class Responsebuilder(val config: ResponseBuilderConfig, param2: int) {
def doSomething() { doSomethingElse(config.configurationValue) }
def doSomethingElse(param: String) { ...
}

class ResponseBuilderSpec extends Specification with Mockito {
"response builder" should {
"respond" in {
val mockConfig = mock[ResponseBuilderConfig]
mockConfig.configurationValue returns "Test"
val testClass = spy(new ResponseBuilder(mockConfig, 3))
testClass.doSomething()

there was one(testClass).doSomethingElse("Test")
}
}
}

How can I mock a method that has a parameter with a private constructor?

This boils down to the visibility of the SimpleCacheKey class, you simply can't use it from a different package. So Mockito.any() can't use that class as a return type unless the unit test is in the same package as SimpleCacheClient.

One solution would be to move your unit test to the same package as SimpleCacheClient. If this is loaded from a different library that you can't change, you can re-create the same package structure to trick the compiler into thinking the package is the same, giving you access to protected classes.
But i believe this trick doesn't work with Java 9 modules.

A better solution would be to make a small modification to your CacheClientImplementation and unit test; encapsulate the part you can't influence and mock that part.

Since you don't really care about the SimpleCacheKey but just the String key, the following should work for your intentions:

public class CacheClientImplementation extends SimpleCacheClient<ArrayList<DateTime>> {
public void addEventDateTimes(String key, ArrayList<DateTime> eventDateTimes) {
// Do stuff with eventDateTimes and then
setForKey(key, eventDateTimes);
}

public ArrayList<DateTime> getEventDateTimes(String key) {
ArrayList<DateTime> eventDateTimes = getForKey(key);
// Do stuff with eventDateTimes.
return eventDateTimes;
}

protected ArrayList<DateTime> getForKey(String key) {
return super.get(getCacheKey(key));
}

protected void setForKey(String key, ArrayList<DateTime> value) {
super.set(getCacheKey(key), value);
}
}

And in the unit test you rewrite to the forKey variants we just created:

Mockito.doAnswer(myAnswer1()).when(cacheClient).setForKey(Mockito.any(), Mockito.any(ArrayList.class));
Mockito.doAnswer(myAnswer2()).when(cacheClient).getForKey(Mockito.any());

I've made the new methods protected as to not confuse callers which method to use, so in this case the unit test must be in same (test) package as the CacheClientImplementation.



Related Topics



Leave a reply



Submit