具有依赖性的单元测试静态方法

时间:2014-06-11 09:02:54

标签: android junit mockito

我在单元测试方面没有太多经验,尤其是Mockito,现在我遇到了以下情况。

class A {

    void setField(String obj) {
    }

    Object execute() {
        throw new RuntimeException("Meh!");
    }

}

class B {
    //function to be tested
    static Object someMethod() {

        A a = new A();
        a.setField("test");
        Object response = a.execute();
        //logic here

        return response;
    }
}

class BTest() {

   A aInstance = mock(A.class);

   @Test
   public void test_someMethod_when_exec_returns_X() {
      when(aInstance.execute()).thenReturns("X");// doesn’t work
      assertTrue("X", B.someMethod());
   }
}

我想在a.execute()返回特定值时测试someMethod静态方法。 我知道,我可以创建A的模拟对象并将其传递给someMethod函数,这不是一个好的解决方案,因为我应该更改someMethod的签名。

在这种情况下,正确的解决方案是什么?

2 个答案:

答案 0 :(得分:2)

如果您查看PowerMockito's documentation,您会发现以下内容符合您的要求:

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

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.powermock.api.mockito.PowerMockito.mock;
import static org.powermock.api.mockito.PowerMockito.whenNew;

// execute the test with the appropriate runner
@RunWith(PowerMockRunner.class)

// prepare B for instrumentation so we can hack stuff inside
@PrepareForTest(B.class)
public class MyTest {

    @Test
    public void bShouldCallA() throws Exception {
        // create a mock for A and configure its behaviour
        A aMock = mock(A.class);
        when(aMock.execute()).thenReturn("X");

        // make sure that when A's constructor is called in the static method, the mock above is returned
        whenNew(A.class).withNoArguments().thenReturn(aMock);

        // do the actual invocation
        Object actualResult = B.someMethod();

        // check result and interactions
        assertEquals("X", actualResult);
        verify(aMock).setField("test");
    }
}

答案 1 :(得分:1)

正如我所提到的,PowerMockito在android中不起作用,你可以用它来模拟android对象。这是工程解决方案:)

用于创建对象A的工厂类。

public class AFactory {

  static private AFactory sInsntance = new AFactory(); 

  public static AFactory createObject() {
      return sInsntance.createInternally();
  }

  protected TMMethodBuilder createInternally() {
     return new A();
  }

  //This function is only for testing, in order to inject factory
  @Deprecated
  public static void setFactory(AFactory mock) {
      sInsntance = mock;
  }
}

创建对象A:

A a = AFactory.createObject();

在Test项目中扩展AFactory并覆盖createInternally()方法以返回模拟对象。

public class AFactoryTest extends AFactory {

  private static A a = mock(A.class);

  @Override
  protected TMMethodBuilder createInternally()  {
      return a;
  } 
}

因此,在测试类中,只需执行以下操作:

    factory = new AFactoryTest();
    a = factory.createInternally();
    AFactory.setFactory(factory);
    //
    when(..).thenReturn();