Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/elixir/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何处理模拟对象中的差异?_Java_Unit Testing_Junit_Mocking - Fatal编程技术网

Java 如何处理模拟对象中的差异?

Java 如何处理模拟对象中的差异?,java,unit-testing,junit,mocking,Java,Unit Testing,Junit,Mocking,假设我有以下要模拟的界面: Searcher.java public interface Searcher { public String search(); public void someMethod(); } 当我想为这个接口使用不同的模拟实现时,我该怎么做?例如,在一个测试中,我希望让search()方法返回空字符串,在另一个测试中,我希望它开始执行一些HTTP请求等 我是否封装了行为,比如fx。将其放入SearchBehavior接口,然后为该接口编写实现: p

假设我有以下要模拟的界面:

Searcher.java

public interface Searcher {

    public String search();

    public void someMethod();

}
当我想为这个接口使用不同的模拟实现时,我该怎么做?例如,在一个测试中,我希望让
search()
方法返回空字符串,在另一个测试中,我希望它开始执行一些HTTP请求等

我是否封装了行为,比如fx。将其放入SearchBehavior接口,然后为该接口编写实现:

public class SearcherMock implements Searcher {

    private SearchBehaviour searchBehaviour;

    public SearcherMock(SearchBehaviour searchBehaviour) {
        this.searchBehaviour = searchBehaviour;
    }

    @Override
    public String search() {
        return searchBehaviour.search();
    }

    @Override
    public void someMethod() {
        // Do something here
    }

} 

还是为每个不同的模拟实现创建一个新的模拟类?外汇
EmptySearcher
HTTPSearcher

我建议您使用java模拟工具,例如or,它不会让您自己编写模拟工具,而是编写好的模拟,从而节省您的时间:)

使用Mockito,您可以执行以下操作(但未经测试):


我建议您使用诸如或之类的java模拟工具,这样可以节省一些时间,因为不允许您自己编写模拟工具,而是编写好的模拟:)

使用Mockito,您可以执行以下操作(但未经测试):


请记住,您可以为不同的测试自由创建匿名内部类,而无需使用库:

@Test public void test1() {
  // When referring to outside local variables, they must be final.
  final AtomicBoolean someMethodCalled = new AtomicBoolean(false);

  Searcher fakeSearcher = new Searcher() {
    @Override public String search() {
      return "stubbed return value";
    }

    @Override public void someMethod() {
      someMethodCalled.set(true);
    }       
  };
  SystemUnderTest systemUnderTest = new SystemUnderTest(fakeSearcher);
  systemUnderTest.pressBigRedButton();
  assertTrue("someMethod should have been called", someMethodCalled.get());
}
甚至变得相当聪明:

private Searcher createFakeSearcher(final String... searchResults) {
  return new Searcher() {
    int returnIndex = 0;

    @Override public String search() {
      return searchResults[returnIndex++];
    }

    @Override public void someMethod() {}       
  };
}
但是花一些时间学习模拟框架将很好地服务于您和您的测试,因为像Mockito这样的框架是为了去掉样板文件而设计的:

// Uses static imports from org.mockito.Mockito;
@Test public void test1() {
  Searcher mockSearcher = mock(Searcher.class);
  when(mockSearcher.search())
      .thenReturn("search one")
      .thenReturn("search two")
      .thenThrow(new IllegalStateException());

  SystemUnderTest systemUnderTest = new SystemUnderTest(mockSearcher);
  systemUnderTest.pressBigRedButton();
  verify(mockSearcher, times(2)).someMethod();
}

要更好地从概念上介绍双重测试(Dummie/stubs/Mock/fakes)以及它们之间的差异,请阅读或深入阅读。

请记住,您可以在不使用库的情况下为不同的测试自由创建匿名内部类:

@Test public void test1() {
  // When referring to outside local variables, they must be final.
  final AtomicBoolean someMethodCalled = new AtomicBoolean(false);

  Searcher fakeSearcher = new Searcher() {
    @Override public String search() {
      return "stubbed return value";
    }

    @Override public void someMethod() {
      someMethodCalled.set(true);
    }       
  };
  SystemUnderTest systemUnderTest = new SystemUnderTest(fakeSearcher);
  systemUnderTest.pressBigRedButton();
  assertTrue("someMethod should have been called", someMethodCalled.get());
}
甚至变得相当聪明:

private Searcher createFakeSearcher(final String... searchResults) {
  return new Searcher() {
    int returnIndex = 0;

    @Override public String search() {
      return searchResults[returnIndex++];
    }

    @Override public void someMethod() {}       
  };
}
但是花一些时间学习模拟框架将很好地服务于您和您的测试,因为像Mockito这样的框架是为了去掉样板文件而设计的:

// Uses static imports from org.mockito.Mockito;
@Test public void test1() {
  Searcher mockSearcher = mock(Searcher.class);
  when(mockSearcher.search())
      .thenReturn("search one")
      .thenReturn("search two")
      .thenThrow(new IllegalStateException());

  SystemUnderTest systemUnderTest = new SystemUnderTest(mockSearcher);
  systemUnderTest.pressBigRedButton();
  verify(mockSearcher, times(2)).someMethod();
}

要更好地从概念上介绍双重测试(假人/存根/模拟/假货)以及它们之间的区别,请阅读或深入阅读。

您可以使用类似Mockito的模拟框架,并使用JUnitParams参数化您的测试

假设您有一个验证Searcher的类,如果search返回“valid”,它将通过。代码和测试如下所示,有两个测试用例,一个用于有效搜索结果,一个用于无效搜索结果

public class SomeClass {
    public boolean isValid(Searcher searcher) {
        return searcher.search().equals("valid");
    }
}

@RunWith(JUnitParamsRunner.class)
public class SomeClassTest {

    public Object[] provideIsValid() {
        return new Object[]{
                new Object[]{ "invalid", false },
                new Object[]{ "valid", true }
        };
    }

    @Test
    @Parameters(method = "provideIsValid")
    public void testIsValid(String output, String expected) {
        SomeClass someClass = new SomeClass();
        Searcher mock = mock(Searcher.class);
        when(mock.search()).thenReturn(output);

        String actual = someClass.isValid(mock);
        assertEquals(expected, actual);
    }

您可以使用类似Mockito的模拟框架,并使用JUnitParams参数化您的测试

假设您有一个验证Searcher的类,如果search返回“valid”,它将通过。代码和测试如下所示,有两个测试用例,一个用于有效搜索结果,一个用于无效搜索结果

public class SomeClass {
    public boolean isValid(Searcher searcher) {
        return searcher.search().equals("valid");
    }
}

@RunWith(JUnitParamsRunner.class)
public class SomeClassTest {

    public Object[] provideIsValid() {
        return new Object[]{
                new Object[]{ "invalid", false },
                new Object[]{ "valid", true }
        };
    }

    @Test
    @Parameters(method = "provideIsValid")
    public void testIsValid(String output, String expected) {
        SomeClass someClass = new SomeClass();
        Searcher mock = mock(Searcher.class);
        when(mock.search()).thenReturn(output);

        String actual = someClass.isValid(mock);
        assertEquals(expected, actual);
    }

单元测试的HTTP请求?考虑到您的接口(不会引发任何类型的异常;如果请求失败怎么办?),听起来很可疑。不管HTTP部分是什么,它只是用于说明差异,我认为您不想这样做;真正的模拟不会运行复杂的代码。您将让它返回您想要的值,以便可以测试该模拟的用户。也就是说,使用mockito,你会在(searcher.search())时执行
,然后返回(“某物”).HTTP请求进行单元测试?考虑到您的接口(不会引发任何类型的异常;如果请求失败怎么办?),听起来很可疑。不管HTTP部分是什么,它只是用于说明差异,我认为您不想这样做;真正的模拟不会运行复杂的代码。您将让它返回您想要的值,以便可以测试该模拟的用户。也就是说,使用mockito,你会在(searcher.search())时执行
,然后返回(“某物”)
.OP,请注意,JUnit4有一个内置的运行程序,但提供了一些其他特性。这两种方法都适用于您所询问的变体。请注意,JUnit4有一个内置的runner,但提供了更多的功能。这两种方法都适用于您所询问的变体。