全部关于测试–第3部分

在前两篇 文章中,我主要讨论了使用测试进行开发的理念和态度。 在这篇文章中,我提供了一些提示和工具示例进行测试。

工具类

JUnit的

http://junit.org/
还有TestNG,这是个很棒的工具。 但是我对JUnit有更多的经验,因此我将描述这个框架。

  1. 使用最新版本。
  2. 了解您的测试工具!
  • @RunWith
    这是类注释。 它告诉JUnit使用不同的Runner运行(mockito和Spring运行器是我使用的最常见的运行器)
    import org.mockito.runners.MockitoJUnitRunner;
    ...
    @RunWith(MockitoJUnitRunner.class)
    public class MyClassTest {
      ...
    }
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = { "/META-INF/app-context.xml","classpath:anotherContext.xml" })
    public class MyClassTest {
      ...
    }
    // You can inherit AbstractJUnit4SpringContextTests instead of using runner
  • @规则
    一种AOP。 最常见的即用型规则是TemporaryFolder规则。 它使您可以使用文件系统而不必担心打开和关闭文件。 规则示例可在此处找到。
  • 参数化流道
    真的很酷的工具。 它使您可以使用不同的输入和不同的预期输出运行相同的测试。 它可能会被滥用,并使其无法读取。
  • 测试数据准备和维护技巧
Hamcrest

http://hamcrest.org/JavaHamcrest/
该库是JUnit的“扩展”。 没有它,我无法工作! Hamcrest库为我们提供了开箱即用的匹配器。 匹配器与assertThat(...,Matcher)风格一起使用。 我几乎总是用这种味道。 (在上一篇文章中,有人建议我不应该使用assertTrue(…),而应该使用assertThat。) 匹配器类型很多:您可以忽略集合来验证集合中的现有对象。 您可以检查大于。 使用assertThat +匹配器可以使测试更具可读性。

assertThat(mapAsCache.containsKey(new CacheKey("valA", "valB")), is(true));
assertThat(cachPairs.size(), is(2));
assertThat(enity.getSomething(), nullValue(Double.class));
assertThat(event.getType(), equalTo(Type.SHOWN));
assertThat(bits, containsInAnyOrder(longsFromUsIndexOne, longsFromUsIndexZero));

您可以创建自己的Matcher。 很简单 这是一个验证正则表达式的匹配器示例。 https://github.com/eyalgo/junit-additions

模仿

https://code.google.com/p/mockito/
这是我不能没有的第二个图书馆。 它使您可以模拟被测类的依赖关系。 使用mockito可以模拟依赖项。 然后,您“告诉”模拟对象在某些输入中的行为。 您告诉它如果输入了一些输入将返回什么。 您可以验证被调用方法的输入参数。 您可以验证是否调用了某个方法(一次,从不,3次,等等)。 您可以检查方法/模拟调用的顺序。

看一下这个:

package eyalgo;
 
import static org.hamcrest.Matchers.equalTo;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.argThat;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
 
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InOrder;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
 
//The RunWith automatically instantiate fields with @Mock annotation
//and injects to the tested class @InjectMocks
@RunWith(MockitoJUnitRunner.class)
public class NameConnectorTest {
	@Mock
	private NameConvention nameConventionAsMockField;
	
	@InjectMocks
	private NameConnector connector;
	
	private NameConvention nameConventionAsMockOther;
	
	@Before
	public void setup() {
		//This is another way to inject mocks (instead of the annotations above)
		MockitoAnnotations.initMocks(this);
		nameConventionAsMockOther = mock(NameConvention.class);
		NameConnector otherConnector = new NameConnector(nameConventionAsMockOther);
	}
	
	@Test
	public void showSomeMockitoExamples() {
		NameConvention nameConventionAsMock = mock(NameConvention.class, "Name for this mock");
		
		// Stub and tell your mock to do something
		when(nameConventionAsMock.bigBangConvention("INPUT")).thenReturn("Some output");
		
		// Throw exception for some input
		when(nameConventionAsMock.bigBangConvention("Other INPUT")).thenThrow(new RuntimeException("oops"));
		
		// Do more complicated stuff in the "when"
		Answer answer = new Answer() {
 
			@Override
			public String answer(InvocationOnMock invocation) throws Throwable {
				//do something really complicated
				return "some output";
			}
		};
		//Show also hamcrest matchers
		when(nameConventionAsMock.bigBangConvention(argThat(equalTo("my name is Inigo Montoya")))).then(answer);
		
		// Run the test..
		
		//Verify some calls
		verify(nameConventionAsMock).bigBangConvention("INPUT");
		verify(nameConventionAsMock, times(10)).bigBangConvention("wow");
		
		// Verify that the method was never called. With any input
		verify(nameConventionAsMock, never()).bigBangConvention(anyString());
		
		verifyNoMoreInteractions(nameConventionAsMock);
		verifyZeroInteractions(nameConventionAsMockField);
		
		//Check order of calls
		InOrder order = inOrder(nameConventionAsMock, nameConventionAsMockOther);
		order.verify(nameConventionAsMock).bigBangConvention("INPUT");
		order.verify(nameConventionAsMock).bigBangConvention("other INPUT");
		
	}
}
其他模拟工具
杰贝夫

http://jbehave.org/
JUnit,mockito,hamcrest用于单元测试 。 JBehave不完全相同。 它是用于行为驱动开发(BDD)的工具,您可以编写由代码(Java)备份的故事 ,然后运行它们。 JBehave可用于更高级别的测试,例如功能测试。 使用JBehave,可以更轻松地测试系统中的流。 它遵循给定,何时,然后顺序。 如果继续进行下一步,它可能是一个很好的交流工具。 产品负责人可以编写方案,如果所有方案都是绿色的,则在迭代结束时,我们传递了done定义黄瓜是另一个BDD工具。

依赖注入

为了拥有可测试的代码,除其他外,您需要练习DI(依赖注入)。 原因很简单:如果在被测类的构造函数(或方法)中实例化依赖项,那么如何模拟它? 如果您无法模拟依赖项,那么您将受到约束。 而且您无法模拟不同的情况。 许多应用程序都将Spring用作DI容器,但是较少的开发人员会利用使用注入进行测试的优势。

指标

在您的CI环境中使用SONAR 。 使用cobertura或其他工具检查代码覆盖率。 使用Jenkins / Hudson / Other CI工具进行自动化。

集成开发环境

您的IDE可以帮助您编写测试。
对于日食,我有两个建议:

    1. MoreUnit是一个很棒的插件,可以帮助更快地编写测试。
    2. 在Eclipse中,CTRL + Space可以给您提示并填充导入。 但不是静态导入。 大多数(全部?)库都使用静态导入。 因此,您可以将测试库添加为收藏夹,然后eclipse会为您填充它们。
蚀收藏夹

蚀收藏夹

聚甲醛

这是用于测试库的POM的一部分。

<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<configuration>
					<source>1.8</source>
					<target>1.8</target>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-jar-plugin</artifactId>
				<configuration>
					<archive>
						<addMavenDescriptor>false</addMavenDescriptor>
					</archive>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-source-plugin</artifactId>
				<executions>
					<execution>
						<goals>
							<goal>jar-no-fork</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
			<plugin>
				<artifactId>maven-assembly-plugin</artifactId>
				<configuration>
					<archive>
						<manifest>
							<mainClass>com.startapp.CouchRunner.GetUserProfile</mainClass>
						</manifest>
					</archive>
					<descriptorRefs>
						<descriptorRef>jar-with-dependencies</descriptorRef>
					</descriptorRefs>
				</configuration>
			</plugin>
		</plugins>
	</build>

您可以检查方法/模拟调用的顺序。

您可以使用概要文件将单元测试与集成测试分开。

翻译自: https://www.javacodegeeks.com/2014/11/its-all-about-tests-part-3.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值