-1

I need to create a unit test for the following case:

Class under test:

class MyProducer {

private Producer producer = null;
private ProducerCreator producerCreator = null;

public MyProducer() {
 producerCreator = ProducerCreator.create(string name);
 producer = producerCreator.createProducer();

}
public boolean foo() {
  return producer.foo();
}
}

The class ProducerCreator is from an external package with no source code:

public interface ProducerCreator {

static default ProducerCreator create(String name) {
  return new ProducerCreatorImpl(...)
  }
 }

So I am trying to mock the static call with PowerMockito:

@RunWith(PowerMockRunner.class)
@PrepareForTest(ProducerCreator.class)
public class ProducerTest {

    @Test
    public void fooTest() {


        ProducerCreator producerCreatorMock = Mockito.mock(ProducerCreator.class);

 PowerMockito.mockStatic(ProducerCreator.class); 
 PowerMockito.when(ProducerCreator.class, "createProducer", "name").thenReturn(producerCreatorMock);

(Also tried this:

PowerMockito.when(ProducerCreator.create("name")).thenReturn(producerCreatorMock);

But it didn't do any change )

        MyProducer myProducer = new MyProducer();


    assertTrue(myProducer.foo());



}

Generally I get something like the following:

org.mockito.exceptions.misusing.UnfinishedStubbingException: 
...
E.g. thenReturn() may be missing.
Examples of correct stubbing:
    when(mock.isOk()).thenReturn(true);
    when(mock.isOk()).thenThrow(exception);
    doThrow(exception).when(mock).someVoidMethod();
Hints:
 1. missing thenReturn()
 2. you are trying to stub a final method, you naughty developer!
 3: you are stubbing the behaviour of another mock inside before 'thenReturn' instruction if completed

Or any other error or unwanted behaviour instead of a proper mocking. Is the issue due to "static default" method in interface? Didn't find any example for such case in Internet.

UPD: I can't share the real code as it is proprietary.

There is a real static default method from an external package that does compile:

public interface ProducerCreator extends Closeable {
    static default ProducerCreator create(String serviceUrl) throws ProducerCreatorException {
        return ...
    }

UPD 2: The package is a JNI package - generated from CPP code..

Eric Abramov
  • 462
  • 4
  • 19
  • 2
    are you sure the method is both default and static.. that combination would result in compilation error. – Maciej Kowalski Jun 22 '17 at 13:25
  • Sure, sure. I see the code:) – Eric Abramov Jun 22 '17 at 13:30
  • 2
    You cannot have an interface method that's both `static` and `default`. That "sure, sure" tells us that you haven't tried to compile your code sample and aren't doing due diligence. What does "I see the code" even mean? That response invalidates your question. http://docs.oracle.com/javase/specs/jls/se8/html/jls-9.html#jls-9.4 "It is a compile-time error if a method is declared with more than one of the modifiers `abstract`, `default`, or `static`." Show us your _real_ code please. What you showed cannot compile. – Lew Bloch Jun 22 '17 at 13:38
  • It turns out that it is a JNI package generated from C++ code – Eric Abramov Jun 22 '17 at 13:58
  • @MaciejKowalski so what can you say now? – Eric Abramov Jun 22 '17 at 14:09

1 Answers1

0

Your code does not compile. I have made some assumptions:

public class Producer {
    public boolean foo(){
        return true;
    }
}

public interface ProducerCreator {
    public static ProducerCreator create(String name) {
        return new ProducerCreatorImpl(name);
    }

    Producer  createProducer();
}

public class MyProducer {

    private Producer producer = null;
    private ProducerCreator producerCreator = null;

    public MyProducer() {
        producerCreator = create("name");
        producer = producerCreator.createProducer();

    }
    public boolean foo() {
        return producer.foo();
    }
}
public class ProducerCreatorImpl implements ProducerCreator{


    public ProducerCreatorImpl(String name) {

    }

    @Override
    public Producer createProducer() {
        return new Producer();
    }
}

And your test, which works for me:

@RunWith(PowerMockRunner.class)
@PrepareForTest({ ProducerCreator.class })
public class DatasourceTest {

    @Test
    public void fooTest() {


        ProducerCreator producerCreatorMock = Mockito.mock(ProducerCreator.class);

        PowerMockito.mockStatic(ProducerCreator.class);
        PowerMockito.when(ProducerCreator.create(Mockito.anyString())).thenReturn(producerCreatorMock);

        Producer prodMock = Mockito.mock(Producer.class);
        Mockito.when(producerCreatorMock.createProducer()).thenReturn(prodMock);
        Mockito.when(prodMock.foo()).thenReturn(false);

        MyProducer myProducer = new MyProducer();
        boolean result = myProducer.foo();

        Assert.assertFalse(result);

        Mockito.verify(prodMock).foo();

    }
}
kism3t
  • 1,343
  • 1
  • 14
  • 33
  • The code I put here is an abstraction of the real code which I can't publish. In your example the interface function if static, but not default. If you add default keyword, does it work? – Eric Abramov Jun 22 '17 at 13:37
  • No, as @Macijej commented on your question, it does not compile. It is an illegal combination of static and default. I added some more elaborate test, which actually tests something – kism3t Jun 22 '17 at 13:39
  • What about JNI? – kism3t Jun 22 '17 at 14:12
  • Read the updates. The static default is from a JNI pacakge. – Eric Abramov Jun 22 '17 at 14:31