测试。 最近我一直在考虑进行测试。 作为我对各种项目所做的代码审查的一部分,我已经看到了数千行未经测试的代码。 这不仅是测试覆盖率统计数据指出这一点的情况,还更多是该项目中根本没有任何测试的情况 。 我一直听到这种悲惨状况的两个原因? “我们没有时间”,紧随其后的是“完成代码后就去做”。
我在这里展示的不是万能药。 它涵盖了单元测试,尤其是接口的单元测试。 接口是好东西。 接口定义合同。 接口,无论接口有多少种实现方式,都可以轻松,轻松地进行测试。 让我们看看如何使用此类结构作为示例。
CustomerService是我们的界面。 为了使示例保持简单,它有两种方法,下面将进行介绍。 注意javadoc-这是描述合同的地方。
public interface CustomerService
{
/**
* Retrieve the customer from somewhere.
* @param userName the userName of the customer
* @return a non-null Customer instance compliant with the userName
* @throws CustomerNotFoundException if a customer with the given user name can not be found
*/
Customer get(String userName) throws CustomerNotFoundException;
/**
* Persist the customer.
* @param customer the customer to persist
* @return the customer as it now exists in its persisted form
* @throws DuplicateCustomerException if a customer with the user name already exists
*/
Customer create(Customer customer) throws DuplicateCustomerException;
}
从图中可以看到,我们有两个此类的实现,RemoteCustomerService和CachingCustomerService。 这些的实现没有显示,因为它们无关紧要。 我怎么说呢 很简单–我们正在测试合同。 我们为接口中的每个方法以及合同的每个排列编写测试。 例如,对于get(),我们需要测试存在具有给定用户名的客户时发生的情况,以及不存在时发生的情况。
public abstract class CustomerServiceTest
{
@Test
public void testCreate()
{
CustomerService customerService = getCustomerService();
Customer customer = customerService.create(new Customer("userNameA"));
Assert.assertNotNull(customer);
Assert.assertEquals("userNameA",
customer.getUserName());
}
@Test(expected = DuplicateCustomerException.class)
public void testCreate_duplicate()
{
CustomerService customerService = getCustomerService();
Customer customer = new Customer("userNameA");
customerService.create(customer);
customerService.create(customer);
}
@Test
public void testGet()
{
CustomerService customerService = getCustomerService();
customerService.create(new Customer("userNameA"));
Customer customer = customerService.get("userNameA");
Assert.assertNotNull(customer);
Assert.assertEquals("userNameA",
result.getUserName());
}
@Test(expected = CustomerNotFoundException.class)
public void testGet_noUser()
{
CustomerService customerService = getCustomerService();
customerService.get("userNameA");
}
public abstract CustomerService getCustomerService();
}
现在,我们已经对合同进行了测试,并且在任何时候都没有提到任何实现。 这意味着两件事:
- 我们不需要为每个实现重复测试。 这是一件非常好的事情。
- 没有一个实现正在测试中。 我们可以通过为每个实现添加一个测试类来纠正此问题。 由于每个测试类几乎都是相同的,因此我将仅演示RemoteCustomerService的测试。
public class RemoteCustomerServiceTest extends CustomerServiceTest
{
public CustomerService getCustomerService()
{
return new RemoteCustomerService();
}
}
就是这样! 现在,我们有了一种非常简单的方法来测试任何接口的多个实现,方法是预先进行艰苦的工作,并将测试新实现的工作减少到一个简单的方法中。
翻译自: https://www.javacodegeeks.com/2013/06/a-good-lazy-way-to-write-tests.html