EasyMock教程
EasyMock是基于Java的模拟框架,可与其他单元测试框架(例如JUnit和TestNG)结合使用。
EasyMock与Mockito模拟框架非常相似。
EasyMock允许我们创建接口和具体类的模拟对象并指定其行为。
然后,我们可以使用这些模拟程序编写代码来测试我们的主类。
这种方式简化了编写单元测试的过程,因为我们无需关心外部依赖项。
EasyMock
我们可以使用EasyMock创建模拟对象,然后将它们注入到我们要测试的类中。
但是,EasyMock也有某些限制。
EasyMock无法模拟最终方法和私有方法。
如果在模拟对象上调用了这些方法,则将调用普通方法。EasyMock为equals(),toString(),hashCode()和finalize()方法提供了内置行为。
这意味着我们无法记录这些方法的行为。
EasyMock Maven依赖关系
我们可以将以下依赖项添加到我们的maven项目中,以使用EasyMock模拟框架。
<dependency> <groupId>org.easymock</groupId> <artifactId>easymock</artifactId> <version>3.6</version> <scope>test</scope> </dependency>
EasyMock教程
让我们创建一些示例类和服务来进行模拟。
我们将使用JUnit 5编写测试用例,并使用EasyMock来创建模拟对象。
package com.theitroad.utils; public interface Calculator { int add(int x, int y); int multiply(int x, int y); }
package com.theitroad.utils; public class MathUtils { private Calculator calc; public MathUtils(Calculator c) { this.calc = c; } public int add(int i, int j) { return this.calc.add(i, j); } public int multiply(int i, int j) { return this.calc.multiply(i, j); } }
请注意,由于我们正在模拟测试用例,因此无需使用计算器实现即可编写测试用例。
这样,我们可以在我们的应用程序中应用测试驱动开发(TDD)模型。
org.easymock.EasyMock`类提供了大多数有用的方法。
由于它们大部分是静态的,因此我们可以将其导入以编写流利且更具可读性的代码。
我们还可以模拟一个具体的类并指定其行为。
我们首先来看一个简单的示例,在该示例中我们将模拟ArrayList类。
package com.theitroad.easymock; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.mock; import static org.easymock.EasyMock.replay; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.ArrayList; import org.junit.jupiter.api.Test; public class EasyMockMethodExample { @Test public void test() { ArrayList<Integer> mockList = mock(ArrayList.class); expect(mockList.add(10)).andReturn(true); expect(mockList.add(20)).andReturn(true); expect(mockList.size()).andReturn(2); expect(mockList.get(0)).andReturn(10); replay(mockList); mockList.add(10); mockList.add(20); //below will throw exception because it's not mocked //mockList.add(30); assertTrue(mockList.get(0) == 10); assertEquals(mockList.size(), 2); } }
从EasyMock示例上面要注意的一些重要点是:
第一步是使用EasyMock
mock()
方法创建模拟对象。
这个方法是重载的,在这里我们可以指定我们想要的模拟对象是好还是严格。
我们还可以指定在记录异常时使用的名称。
我们将在以后的文章中研究不同的" MockType"示例。下一步是使用
expect()
和andReturn()
链语句对方法调用的行为和输出进行存根。最后,我们必须调用replay()方法来开始在模拟对象上使用存根方法。
如果我们调用一个未存根的方法,则将得到java.lang.AssertionError。
EasyMock注释– @ Mock,@ TestSubject
EasyMock还提供了一些注释来创建模拟对象。
@Mock:用于指定EasyMock模拟的字段。
@TestSubject与字段一起使用,以便EasyMock将在其字段上注入使用@Mock创建的模拟。
使用批注时,我们必须使用" EasyMockRunner"," EasyMockRule"或者" EasyMockSupport.injectMocks(Object)"来初始化和注入模拟对象。
由于我们使用的是JUnit-5,因此我们不能使用EasyMockRunner和EasyMockRule,因为它们尚未支持。
因此,我们将不得不使用EasyMockSupport.injectMocks(Object)
。
我们可以在@ BeforeEach
方法中调用此方法。
这是使用EasyMock注释模拟对象的完整示例。
package com.theitroad.easymock; import static org.easymock.EasyMock.*; import static org.junit.jupiter.api.Assertions.*; import org.easymock.EasyMockSupport; import org.easymock.Mock; import org.easymock.TestSubject; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import com.theitroad.utils.Calculator; import com.theitroad.utils.MathUtils; public class EasyMockAnnotationExample { @Mock private Calculator mockCalculator; @TestSubject private MathUtils mathUtils = new MathUtils(mockCalculator); @BeforeEach public void setup() { EasyMockSupport.injectMocks(this); } @Test public void test() { expect(mockCalculator.add(1, 1)).andReturn(2); expect(mockCalculator.multiply(10, 10)).andReturn(100); replay(mockCalculator); assertEquals(mathUtils.add(1, 1), 2); assertEquals(mathUtils.multiply(10, 10), 100); } }
EasyMock迭代器样式存根
我们可以通过将它们与times()链接起来,为相同的方法调用指定不同的行为。
让我们看一个简单的例子来清楚地理解这一点。
//Iterator Style Mocking reset(mockList); expect(mockList.size()).andReturn(1).times(2) //return 1 for first 2 calls .andReturn(2).times(1) //return 2 for 3rd call .andReturn(4); //return 4 for 4th call replay(mockList); assertEquals(mockList.size(), 1); assertEquals(mockList.size(), 1); assertEquals(mockList.size(), 2); assertEquals(mockList.size(), 4);