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
Convert a String (Like Testing123) to Binary in Java
Java:Why Should We Use Bigdecimal Instead of Double in the Real World
What's Up with Java's "%N" in Printf
Java Error Opening Registry Key
Java Regular Expression to Extract Content Within Square Brackets
Adding Image to Jbutton with Foreground Label
No-Throw Virtualmachineerror Guarantees
What Is the --Release Flag in the Java 9 Compiler
Where Do Java and .Net String Literals Reside
How to Add Unicode in Truetype0Font on PDFbox 2.0.0
Package Conflicts with Automatic Modules in Java 9
How to Keep a Scanner from Throwing Exceptions When the Wrong Type Is Entered
How to Use Aop with Aspectj for Logging
Spring Boot 2.0.X Disable Security for Certain Profile
Configuring Spring Security 3.X to Have Multiple Entry Points