1.介绍

在过去,我们已经广泛地讨论过金宝搏官网188beJMockit5

在本教程中,我们将介绍另一个模仿工具-EasyMock

2.Maven的依赖关系

在深入研究之前,让我们将以下依赖项添加到pom.xml

<依赖> < groupId > org。easymock easymock 3.5.1 test 

总是可以找到最新的版本在这里

3.核心概念

在生成模拟时,我们可以模拟目标对象,指定它的行为,最后验证它是否按预期使用。

使用EasyMock的mock包含四个步骤:

  1. 创建目标类的模拟
  2. 记录其预期行为,包括动作、结果、异常等。
  3. 在测试中使用模拟
  4. 验证它的行为是否符合预期

录制结束后,我们将其切换到“重播”模式,以便mock在与任何将使用它的对象合作时,表现为录制的行为。

最后,我们验证一切是否如预期的那样进行。

上面提到的四个步骤与中的方法有关org.easymock.EasyMock

  1. 模拟(…):生成目标类的模拟,无论是具体类还是接口。一旦创建了mock,它就处于“录制”模式,这意味着EasyMock将记录mock对象采取的任何操作,并在“回放”模式中回放它们
  2. 期望(…)使用此方法,我们可以为相关的记录操作设置期望,包括调用、结果和异常
  3. 重复(…):将给定的mock切换为“重播”模式。然后,触发先前记录的方法调用的任何动作将重放“记录的结果”。
  4. 验证(…):验证是否满足了所有期望,并且没有在mock上执行意外调用

在下一节中,我们将使用实际示例展示这些步骤是如何工作的。

4.一个模仿的实例

在我们继续之前,让我们看一下示例上下文:假设我们有一个Baeldung博客的读者,他喜欢在网站上浏览文章,然后他/她试图写文章。金宝搏188体育

让我们从创建以下模型开始:

public class 金宝搏188体育baeldunreader {private articlerreader;私人IArticleWriter articleWriter;//构造函数public BaeldungAr金宝搏188体育ticle readNext(){return articlerreader .next();} public List<金宝搏188体育BaeldungArticle> readTopic(String topic){return articlerreader . oftopic (topic);} public String write(String title, String content){return文章作者。写(标题、内容);}}

在这个模型中,我们有两个私有成员articleReader(一个具体的类)和articleWriter(接口)。

接下来,我们将对它们进行模拟验证金宝搏188体育BaeldungReader的行为。

5.使用Java代码进行模拟

让我们从嘲笑开始ArticleReader

5.1。典型的嘲笑

我们预计articleReader.next ()当读者跳过一篇文章时要调用的方法:

@Test public void whenReadNext_thenNextArticleRead(){articlerereader mockarticlerereader = mock(articlerereader .class);金宝搏188体育BaeldungReader = new BaeldungReader(mockarticlerreader);期望(mockArticleReader.next ()) .andReturn(空);回放(mockArticleReader);金宝搏188体育baeldungReader.readNext ();验证(mockArticleReader);}

在上面的示例代码中,我们严格遵循4步过程并模拟ArticleReader类。

尽管我们真的不在乎是什么mockArticleReader.next (),我们仍然需要指定一个返回值mockArticleReader.next ()通过使用期望(…).andReturn(…)。

期望(…), EasyMock期望方法返回一个值或抛出一个例外。

如果我们简单地做:

mockArticleReader.next ();回放(mockArticleReader);

EasyMock会抱怨这一点,因为它需要调用金宝搏官网188be期望(…).andReturn(…)如果方法返回任何东西。

如果它是一个无效方法,我们可以预计操作使用expectLastCall ()是这样的:

mockArticleReader.someVoidMethod ();expectLastCall ();回放(mockArticleReader);

5.2。重复订单

如果我们需要按照特定的顺序重新播放动作,我们可以更严格:

@Test public void whenReadNextAndSkimTopics_thenAllAllowed(){articlerreader mockarticlerreader = strictMock(articlerreader .class);金宝搏188体育BaeldungReade baeldungReader = new baeldungReader (mockarticlerreader);期望(mockArticleReader.next ()) .andReturn(空);期望(mockArticleReader.ofTopic(“easymock”)).andReturn(空);回放(mockArticleReader);金宝搏188体育baeldungReader.readNext ();金宝搏188体育baeldungReader.readTopic(“easymock”);验证(mockArticleReader);}

在这个片段中,我们使用strictMock(…)检查方法调用的顺序.创建的模拟模拟(…)strictMock(…),任何意外的方法调用都会导致AssertionError

要允许对mock进行任何方法调用,可以使用niceMock(…)

@Test public void whenReadNextAndOthers_thenAllowed(){articlerereader mockarticlerereader = niceMock(articlerereader .class);金宝搏188体育BaeldungReade baeldungReader = new baeldungReader (mockarticlerreader);期望(mockArticleReader.next ()) .andReturn(空);回放(mockArticleReader);金宝搏188体育baeldungReader.readNext ();金宝搏188体育baeldungReader.readTopic(“easymock”);验证(mockArticleReader);}

这里我们没有预料到金宝搏188体育baeldungReader.readTopic(…)但EasyMock并不会抱怨。与niceMock(……)EasyMock现在只关心目标对象是否执行了预期的操作。

5.3.嘲笑异常抛出

现在,让我们继续模拟接口IArticleWriter,以及如何处理预期throwable

@Test public void whenWriteMaliciousContent_thenArgumentIllegal() {// mock和初始化expect(mockArticleWriter .write("easymock","")) .andT金宝搏188体育hrow(new IllegalArgumentException());回放(mockArticleWriter);//写入恶意内容并捕获异常,如预期的dexception verify(mockArticleWriter);assertequal (IllegalArgumentException.class expectedException.getClass ());}

在上面的代码片段中,我们期望articleWriter是否坚固到足以探测XSS(跨站点脚本)攻击。

所以当读者试图将恶意代码注入文章内容时,作者应该抛出一个IllegalArgumentException.我们用期望(…).andThrow(…)

6.模拟与注释

EasyMock还支持使用注释注入模拟。要使用它们,我们需要运行单元测试EasyMockRunner这样它就能处理@Mock@TestSubject注释。

让我们重写前面的代码片段:

@RunWith(EasyMockRunner.class) public class 金宝搏188体育BaeldungReaderAnnotatedTest {@Mock ArticleReader mockArticleReader;@TestSubject 金宝搏188体育BaeldungReader BaeldungReader = new BaeldungReader();@Test public void whenReadNext_thenNextArticleRead() {expect(mockarticlerreader .next()).andReturn(null);回放(mockArticleReader);金宝搏188体育baeldungReader.readNext ();验证(mockArticleReader);}}

相当于模拟(…), mock将被注入到带注释的字段中@Mock.这些模拟将被注入到带有注释的类的字段中@TestSubject

在上面的代码片段中,我们没有显式初始化articleReader金宝搏188体育baeldungReader。当调用金宝搏188体育baeldungReader.readNext (),我们可以隐式调用mockArticleReader

这是因为mockArticleReader被注入的articleReader字段。

注意,如果我们想要使用另一个测试运行器来代替EasyMockRunner,我们可以使用JUnit测试规则EasyMockRule

public class 金宝搏188体育BaeldungReaderAnnotatedWithRuleTest {@Rule public EasyMockRule mockRule = new EasyMockRule(this);/ /……@Test public void whenReadNext_thenNextArticleRead(){expect(mockarticlerreader .next()).andReturn(null);回放(mockArticleReader);金宝搏188体育baeldungReader.readNext ();验证(mockArticleReader);}}

7.模拟与EasyMockSupport

有时我们需要在一个测试中引入多个模拟,我们必须手动重复:

回放(一个);回放(B);回放(C);/ /……验证(一个);验证(B);验证(C);

这是丑陋的,我们需要一个优雅的解决方案。

幸运的是,我们有一节课EasyMockSupport在EasyMock来帮助解决这个问题它帮助跟踪模拟,这样我们就可以重放并验证它们像这样的一批:

/ /……public class 金宝搏188体育BaeldungReaderMockSupportTest extends EasyMockSupport{//…@Test public void whenReadAndWriteSequencially_thenWorks(){expect(mockarticlerreader .next()). andreturn (null) .times(2)。规划(新NoSuchElementException ());期望(mockArticleWriter。写(“标题”、“内容”)).andReturn(“印度枳- 201801”);replayAll ();//连续执行读写操作verifyAll();assertequal (NoSuchElementException.class expectedException.getClass ());assertequal(“印度枳- 201801”,正如);}}

这里我们嘲笑了两者articleReaderarticleWriter.当将这些模拟设置为“重放”模式时,我们使用了一个静态方法replayAll ()所提供的EasyMockSupport,并使用verifyAll ()批量验证它们的行为。

我们也介绍了*(…)方法预计阶段。它可以帮助指定方法被调用的次数,这样就可以避免引入重复的代码。

我们也可以用EasyMockSupport通过代表团:

EasyMockSupport = new EasyMockSupport();@Test public void whenReadAndWriteSequencially_thenWorks(){ArticleReader mockArticleReader = easyMockSupport .createMock(articlerreader .class);IArticleWriter mockArticleWriter = easyMockSupport .createMock(IArticleWriter.class);金宝搏188体育BaeldungReader = new BaeldungReader(mockarticlerreader, mockArticleWriter);期望(mockArticleReader.next ()) .andReturn(空);期望(mockArticleWriter。写(“标题”、“内容”)).andReturn (" ");easyMockSupport.replayAll ();金宝搏188体育baeldungReader.readNext ();金宝搏188体育baeldungReader。write("title", "content"); easyMockSupport.verifyAll(); }

以前,我们使用静态方法或注释来创建和管理模拟。在内部,这些静态和带注释的模拟是由全局控件控制的EasyMockSupport实例。

在这里,我们显式地实例化了它,并通过委托将所有这些模拟置于自己的控制之下。如果我们的测试代码与EasyMock有任何名称冲突或有任何类似的情况,这可能有助于避免混淆。

8.结论

在本文中,我们简要介绍了EasyMock的基本用法,包括如何生成模拟对象、记录和重放它们的行为,以及验证它们的行为是否正确。金宝搏官网188be

如果你感兴趣,请查看这篇文章以比较EasyMock、Mocket和JMockit。

像往常一样,可以找到完整的实现在Github

通用的底部

从Spring 5和Spring Boot 2开始学习的春天课程:

>>看看课程
这篇文章的评论已经关闭!