web-dev-qa-db-fra.com

Comment se moquer d'une classe singleton enum en utilisant Mockito / Powermock?

Je ne sais pas comment se moquer d'une classe singleton enum.

public enum SingletonObject{
  INSTANCE;
  private int num;

  protected setNum(int num) {
    this.num = num;
  }

  public int getNum() {
    return num;
  }

Je voudrais stub getNum () dans l'exemple ci-dessus, mais je ne peux pas comprendre comment se moquer de la classe SingletonObject réelle. Je pensais que l'utilisation de Powermock pour préparer le test aiderait, car les énumérations sont intrinsèquement finales.

//... rest of test code
@Test
public void test() {
  PowerMockito.mock(SingletonObject.class);
  when(SingletonObject.INSTANCE.getNum()).thenReturn(1); //does not work
}

Cela utilise PowerMockMockito 1.4.10 et Mockito 1.8.5.

22
Sonwright Gomez

Si vous voulez supprimer ce que INSTANCE renvoie, vous pouvez le faire mais c'est un peu méchant (en utilisant la réflexion et la manipulation de bytecode). J'ai créé et testé un projet simple avec trois classes en utilisant le PowerMock 1.4.12/Mockito 1.9.0. Toutes les classes étaient dans le même package.

SingletonObject.Java

public enum SingletonObject {
    INSTANCE;
    private int num;

    protected void setNum(int num) {
        this.num = num;
    }

    public int getNum() {
        return num;
    }
}

SingletonConsumer.Java

public class SingletonConsumer {
    public String consumeSingletonObject() {
        return String.valueOf(SingletonObject.INSTANCE.getNum());
    }
}

SingletonConsumerTest.Java

import static org.junit.Assert.*;
import static org.powermock.api.mockito.PowerMockito.*;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;

@RunWith(PowerMockRunner.class)
@PrepareForTest({SingletonObject.class})
public class SingletonConsumerTest {
    @Test
    public void testConsumeSingletonObject() throws Exception {
        SingletonObject mockInstance = mock(SingletonObject.class);
        Whitebox.setInternalState(SingletonObject.class, "INSTANCE", mockInstance);

        when(mockInstance.getNum()).thenReturn(42);

        assertEquals("42", new SingletonConsumer().consumeSingletonObject());
    }
}

L'appel au Whitebox.setInternalState remplace INSTANCE par un objet factice que vous pouvez manipuler dans votre test.

26
Matt Lachman

Avoir une interface avec les méthodes que vous avez l'intention de simuler

public interface SingletonInterface {
  int getNum();
}

Laissez l'énumération implémenter l'interface

public enum SingletonObject implements SingletonInterface {
    INSTANCE;
    private int num;

    protected void setNum(int num) {
        this.num = num;
    }

    @Override
    public int getNum() {
        return num;
    }
}

Se moquer de l'interface

@Test
public void test() {
  SingletonInterface singleton = Mockito.mock(SingletonInterface.class);
  when(singleton.getNum()).thenReturn(1); //does work
}
0
JavaExcel