对象模拟不起作用(它的 null)和方法调用上的 returns NullPointerException

object mocking is not working (its null) and returns NullPointerException on method call

这里是我的class一个正在测试的-

class A extends ServerResource {
    @Override
    protected void doInit() throws ResourceException {
    }

    @Get
    public String getUsers() {
        String userJson = null;
        // want to mock 
        UserFacade userFacade = new UserFacade();
        // database call: want to return resources
        List<Resource> resources = userFacade.getDrUsersByExample();
        Gson gson = new GsonBuilder().setPrettyPrinting().create();
        userJson = gson.toJson(resources);
        return userJson ;
    }

}

这里是测试class -

@RunWith(MockitoJUnitRunner.class)
class ATest {
    @Mock
    UserFacade userFacade;

    List<Resource> resources;

    @Before
    public void setUp() throws Exception {
      Resource resource = new Resource();
      resource.setName("user");
      resource.setTask("manual");
      resources.add(resource);
    }

    @Test
    public void testUsers() {
      when(userFacade.getDrUsersByExample()).thenReturn(resources);

      A a = new A();

      // causes NullPointerException for userFacade.getDrUsersByExample()
      String userList = a.getUsers();
    }

}

为什么即使在使用 when(userFacade.getDrUsersByExample()).thenReturn(resources) 之后,模拟对象仍会出现 NullPointerException?

Mocked UserFacade 需要显式注入到被测对象中。由于方法内部的 new UserFacade()A 目前与该依赖关系紧密耦合。

紧耦合被认为是代码异味和糟糕的设计。重构 class 以遵循显式依赖原则。

class A extends ServerResource {
    UserFacade userFacade;

    public A(UserFacade userFacade) {
        this.userFacade = userFacade;
    }

    @Override
    protected void doInit() throws ResourceException {
    }

    @Get
    public String getUsers() {
        String userJson = null;
        // database call: want to return resources
        List<Resource> resources = userFacade.getDrUsersByExample();
        Gson gson = new GsonBuilder().setPrettyPrinting().create();
        userJson = gson.toJson(resources);
        return userJson ;
    }
}

然后需要更新测试才能完成。

@Test
public void testUsers() {
    //Arrange
    when(userFacade.getDrUsersByExample()).thenReturn(resources);

    A a = new A(userFacade);

    //Act
    String userList = a.getUsers();

    //Assert
    //...
}

通过从@Nkosi 那里得到提示,我们需要以某种方式将模拟对象传递到正在测试的 class 中,我得到了对我有用的东西-

class A extends ServerResource {
    UserFacade userFacade;

    @Override
    protected void doInit() throws ResourceException {
      this.userFacade = userFacade;
    }

    @Get
    public String getUsers() {
        String userJson = null;
        // database call: want to return resources
        List<Resource> resources = userFacade.getDrUsersByExample();
        Gson gson = new GsonBuilder().setPrettyPrinting().create();
        userJson = gson.toJson(resources);
        return userJson ;
    }

    public void setUserFacade(UserFacade userFacade) {
        this.userFacade= userFacade;
    }
}

然后测试class-

@Test
public void testUsers() {
    //Arrange
    when(userFacade.getDrUsersByExample()).thenReturn(resources);

    A a = new A();
    a.setUserFacade(userFacade);

    //Act
    String userList = a.getUsers();

    //Assert
    //...
}