我一直在使用单元测试。我有一个担忧。
假设我有一个界面和一个实现
public interface UserDAO() {
public User getById(int id);
}
public class UserDAOJdbc implements UserDAO {
private CoolDataSource datasource; //Dependency injection
public User getById(int id) {
User user = this.dataSource.executeSQL("SELECT ....")
return user;
}
}
测试UserDAOJdbc相当容易,只需要注入dataSource对象并用mock替换它,但问题是
有没有一种有效的方法可以防止这种情况发生?在一些场景中嘲笑一种糟糕的方法吗?
答案 0 :(得分:1)
单元测试总是测试实现。测试接口没有意义。如果您有多个UserDAO
实现,则需要编写多个测试。
答案 1 :(得分:1)
我会恭敬地不同意BetaRide并建议测试接口。实现相同接口的不同类将具有相同的功能签名,以不同的方式实现。
例如,假设您有一个IRepository
接口和两个实现DatabaseRepository
和FilesRepository
的实现IRepository
。如果您针对IRepository
进行测试,则FilesRepository
和DatabaseRepository
实施中的此测试可能重用。此外,测试可以由编写接口的程序员编写,之前任何实现类准备就绪。
希望我帮忙!
答案 2 :(得分:0)
如果对DAO进行单元测试,您可以使用Derby或其他可以嵌入到您的应用程序中的小型数据库。您实际上可以创建实体管理器工厂并在setup方法中保持准备。其他方法可以使用它。它不是一个纯粹的单元测试,但可以帮助您轻松测试。
答案 3 :(得分:0)
解决问题的可能方法:
从外部开发您的应用程序。想象一下您当前测试的对象需要的依赖项,但是还没有为它们创建具体的实现。只是推理操作并使用适当的方法签名创建接口。在测试中模拟这些接口。
测试通过后,选择其中一个接口。创建一个抽象基础测试类,并为接口的所有未来实现放置一般测试。这是您的界面的合同,所有实现者都必须尊重。例如:
// High level, implementation-decoupled contract test
public abstract class UserDAOTest {
protected abstract UserDAO getSut();
protected abstract void insertUser(User user);
@Test
public void userFoundReturnsUser() {
User expectedUser = new User(1);
insertUser(expectedUser);
assertEquals(expectedUser, getSut().getById(1));
}
@Test
public void userNotFoundReturnsNull() {
assertNull(getSut().getById(123));
}
@Test (expected=Exception.class)
public void negativeIdthrowsException() {
GetSut().getById(-2);
}
}
创建尽可能多的测试子类,因为您需要在系统中实现接口。在每一个中,覆盖上面定义的抽象测试实用程序方法,以提供特定于实现的详细信息。 JUnit和其他测试框架将自动运行每个派生类的基类的所有测试。添加您可能需要的任何特定于实现的测试。
实施具体类,使测试通过。
跳转到下一个界面。重复。