我最近发现自己编写了一些代码来集成两个不同的平台。 这些系统之一是基于Java的系统,而另一个虽然不是用Java编写的,却提供了Java API。 我将这些系统分别称为Foo和Bar。
在编写一行代码之前就很明显了,但是,测试最终的适配器将需要我显式地模拟后来的系统的API(即Foo),因为我所需要的只是一个jar文件,其类和方法清楚了他们与一个实例进行了交流。
我花了几个周期看一下Java 模拟世界中的新功能,我很高兴看到我的老朋友Mockito仍然很活跃,并且实际上仍然是通用模拟的出色工具 。 对于初学者来说, Mockito是基于Java的模拟框架,它可以:
…味道真的很好。 它使您可以使用[a]简洁的API编写漂亮的测试。 Mockito不会给您带来麻烦,因为这些测试可读性强,并且会产生清晰的验证错误。
Google代码模拟项目页面 –为什么喝呢?
实际上,Mockito提供了一个简单,流畅的API ,使您可以精确地模拟行为而不必大惊小怪。 例如,与Bar进行交互的主要外观是通过QTP
类,该类具有诸如logIn
, logOut
等方法。与其依靠被测类实际调用这些方法,我还可以像这样轻松地使用Mockito创建QTP
模拟实例。 :
模拟QTP实例
QTP qtpThing = mock(QTP.class);
其中, mock
是从org.mockito.Mockito
静态导入的方法。 使用模拟实例,然后我可以指示我希望某些方法如何运行, 只要我将此模拟实例传递给我的被测类即可 。
例如,方法logIn
不返回任何内容。 实际上,必须先调用该方法,然后再调用另一个方法以生成票证(或令牌),该票证将在后续方法调用中使用。 因此,我正在编写的适配器将接收一些输入值(从Foo以XML的形式),并且适配器将返回票证(按照Foo所需的XML模式以XML文档的形式)。
因此,测试这种交互,我需要做两件事:
- 确保使用特定参数调用
logIn
方法 - 通过
getTicket
方法模拟有效票证的响应
而且,我还要验证logIn
失败是否导致适配器代码中发生特定的交互。 因此,我还需要模拟一些异常行为。
在模拟特定方法的情况下,您只需将几个方法链接在一起即可。 在我的情况下, when
and thenReturn
可以像这样进行操作:
模拟getTicket的行为
when(qtpThing.getTicket()).thenReturn("test-ticket");
在上面的代码中,在我的模拟实例上调用getTicket
方法时,将返回String
“ test-ticket”。
接下来,为了确保使用从传入XML文档获得的参数调用logIn
,我可以使用Mockito的verify
方法。
使用Mockito的验证来确保正确的交互
verify(qtpThing, times(1)).logIn("some_value", "some_user_name", "password");
在这种情况下, verify
方法将检查logIn
调用logIn
并传入三个特定的String
值。如果不满足这些期望,则Mockito将引发异常(并且您相应的测试用例将失败)。
因此,用于验证适配器的测试用例非常简单,但可读性很高。
用于验证登录行为的JUnit测试用例
@Test
public void testLoginRequest() throws Exception {QTP qtpThing = mock(QTP.class);when(qtpThing.getTicket()).thenReturn("test-ticket");AdapterRequest request = new AdapterRequest(XML.read("etc/test-login-req.xml"));QbosAdapter adapter = new QbosAdapter();adapter.setQtpInstance(qtpThing);AdapterResponse adapterResponse = adapter.performAction(request);assertNotNull(adapterResponse);verify(qtpThing, times(1)).logIn("some_value", "some_user_name", "password");assertEquals("test-ticket", adapterResponse.getData().getText());
}
如果我需要模拟QTP
对象抛出的异常,表面QTP
是由于无效参数或登录时凭据不正确怎么办? 同样,Mockito的流畅API使这一切变得轻而易举。
就我而言,我希望logIn
方法在其方法签名中抛出一个已检查的方法,该方法名为UnknownQtpException
。 您可以通过doThrow
和when
方法执行此操作。
模拟出Mockito中的异常
doThrow(new UnknownQtpException()).when(qtpThing).logIn("", "blah", "blah");
在上面的代码中,我明确声明,如果logIn
命令的第一个参数为空,则UnknownQtpException
QTP
实例应抛出UnknownQtpException
。 将所有内容放在一起将产生以下测试用例:
使用JUnit和Mockito测试异常情况
@Test
public void testFailureLoginRequest() throws Exception {QTP qtpThing = mock(QTP.class);doThrow(new UnknownQtpException()).when(qtpThing).logIn("", "blah", "blah");XML xml = XML.read("etc/test-login-req-err.xml");AdapterRequest request = new AdapterRequest(xml);QbosAdapter adapter = new QbosAdapter();adapter.setQtpInstance(qtpThing);AdapterResponse adapterResponse = adapter.performAction(request);assertNotNull(adapterResponse);verify(qtpThing, times(1)).logIn("", "blah", "blah");assertEquals("FAILURE", adapterResponse.getData().getText());
}
当然,其优点在于,我的测试用例可以有效地测试我的适配器代码,而无需依赖第三方系统(在本例中为Bar)。 这自然是一种久经考验的测试技术,可在任何语言中使用,值得一试的模拟框架!
如果您发现自己用Java编写了一些集成代码,那么我不推荐Mockito。 Mockito的API非常简单,它使测试易于理解。 我的意思是,它使测试易于吸收。 数字?
翻译自: https://www.javacodegeeks.com/2013/08/imbibing-the-fluency-of-mockito.html