1.介绍
在过去,我们已经广泛地讨论过金宝搏官网188beJMockit和5.
在本教程中,我们将介绍另一个模仿工具-EasyMock.
2.Maven的依赖关系
在深入研究之前,让我们将以下依赖项添加到pom.xml:
<依赖> < groupId > org。easymock easymock 3.5.1 test
总是可以找到最新的版本在这里.
3.核心概念
在生成模拟时,我们可以模拟目标对象,指定它的行为,最后验证它是否按预期使用。
使用EasyMock的mock包含四个步骤:
- 创建目标类的模拟
- 记录其预期行为,包括动作、结果、异常等。
- 在测试中使用模拟
- 验证它的行为是否符合预期
录制结束后,我们将其切换到“重播”模式,以便mock在与任何将使用它的对象合作时,表现为录制的行为。
最后,我们验证一切是否如预期的那样进行。
上面提到的四个步骤与中的方法有关org.easymock.EasyMock:
- 模拟(…):生成目标类的模拟,无论是具体类还是接口。一旦创建了mock,它就处于“录制”模式,这意味着EasyMock将记录mock对象采取的任何操作,并在“回放”模式中回放它们
- 期望(…)使用此方法,我们可以为相关的记录操作设置期望,包括调用、结果和异常
- 重复(…):将给定的mock切换为“重播”模式。然后,触发先前记录的方法调用的任何动作将重放“记录的结果”。
- 验证(…):验证是否满足了所有期望,并且没有在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”,正如);}}
这里我们嘲笑了两者articleReader和articleWriter.当将这些模拟设置为“重放”模式时,我们使用了一个静态方法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.