首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >单元测试、集成测试或设计中的问题?

单元测试、集成测试或设计中的问题?
EN

Stack Overflow用户
提问于 2010-10-03 09:38:17
回答 1查看 748关注 0票数 2

我编写了我的第一个单元测试,我认为它太依赖于其他模块,我不确定这是否是因为:

  • 这是一个复杂的测试
  • 我实际上写了一个集成测试或者
  • 我的设计

有个问题

首先,我要说,虽然我在开发方面有大约4年的经验,但我从未学过自动化测试,也从未教授过自动化测试。

我刚刚用Hibernate完成了DAL实现中的一个重大更改,我的一位同事建议我为新部件编写单元测试。

主要的变化是切换到每个请求的会话模式,以及更有建设性地使用应用程序事务。

由于上述更改的性质,单元测试从特定请求到达并开始事务的点开始,测试在事务结束后结束,并检查事务是否执行了它应该进行的更改。

这一测试涉及初始化以下对象:

内存中的

  • 数据库-这样就会有数据可处理。由于方法依赖于it.
  • Initialize --一个设计为单例的存储库--它是DAL函数的大门,但它也存储其他东西,因此它是一个很大的对象。
  • 初始化请求的处理程序,这也是一个单例方法--这将保存待测试的方法。

我认为我实际上已经编写了一个集成测试,因为我需要插入DB、Hibernate和存储库,但我不知道在其他情况下如何编写它,因为测试方法使用了所有这些对象作为操作,我很想看看事务处理是如何执行的(这是在测试方法上完成的)。

我很感激所有的评论和想法,如果它们不够清楚的话,我很乐意详细说明或澄清这些事情。

谢谢,

伊泰

HibernateSessionFactory实际上是Hibernate In Action书中众所周知的HibernateUtil,由于历史原因而命名错误。

代码语言:javascript
复制
public class AdminMessageRepositoryUpdaterTest {
private static WardId wardId;
private static EmployeeId employeeId;
private static WardId prevWardId;
private static EmployeeId prevEmployeeId;

@Test
public void testHandleEmployeeLoginToWard(){
    AgentEmployeesWardsEngine agentEmployeesWardsEngine = new AgentEmployeesWardsEngine();
    AgentEngine agentEngine = new AgentEngine();
    //Remove all entries from AgentEmployeesWards table
    HibernateSessionFactory.beginTransaction();
    for (Agent agent : agentEngine.findAll()){
        agentEmployeesWardsEngine.removeAgentEntries(agent.getId());
    }
    HibernateSessionFactory.commitTransaction();//no need to try catch as this is done in a controlled environment
    int i=0;
    //build expectedSet
    Set<AgentEmployeesWards> expectedMappingsToChangeSet = new HashSet<AgentEmployeesWards>();
    //Mappings which should have ward updated
    expectedMappingsToChangeSet.add(new AgentEmployeesWards(new AgentId(1).getValue(), employeeId.getValue(), prevWardId.getValue(), true, TimestampUtils.getTimestamp(), i++));
    expectedMappingsToChangeSet.add(new AgentEmployeesWards(new AgentId(2).getValue(), employeeId.getValue(), prevWardId.getValue(), true, TimestampUtils.getTimestamp(), i++));
    //Mappings which should have employee updated
    expectedMappingsToChangeSet.add(new AgentEmployeesWards(new AgentId(3).getValue(), prevEmployeeId .getValue(), wardId.getValue(), false, TimestampUtils.getTimestamp(), i++));
    expectedMappingsToChangeSet.add(new AgentEmployeesWards(new AgentId(4).getValue(), prevEmployeeId.getValue(), wardId.getValue(), false, TimestampUtils.getTimestamp(), i++));

    //Prepare clean data for persistence
    Set<AgentEmployeesWards> cleanSet = new HashSet<AgentEmployeesWards>(expectedMappingsToChangeSet);
    //Mappings which should NOT have ward updated
    cleanSet.add(new AgentEmployeesWards(new AgentId(5).getValue(), employeeId.getValue(), prevWardId.getValue(), false, TimestampUtils.getTimestamp(), i++));
    cleanSet.add(new AgentEmployeesWards(new AgentId(6).getValue(), employeeId.getValue(), prevWardId.getValue(), false, TimestampUtils.getTimestamp(), i++));
    //Mappings which should NOT have employee updated
    cleanSet.add(new AgentEmployeesWards(new AgentId(7).getValue(), prevEmployeeId .getValue(), wardId.getValue(), true, TimestampUtils.getTimestamp(), i++));
    cleanSet.add(new AgentEmployeesWards(new AgentId(8).getValue(), prevEmployeeId.getValue(), wardId.getValue(), true, TimestampUtils.getTimestamp(), i++));
    HibernateSessionFactory.beginTransaction();
    for (AgentEmployeesWards agentEmployeesWards : cleanSet){
        agentEmployeesWardsEngine.saveNewAgentEmployeesWardsEntry(agentEmployeesWards);
    }
    HibernateSessionFactory.commitTransaction();//no need to try catch as this is done in a controlled environment
    //Close the session as to neutralize first-level-cache issues
    HibernateSessionFactory.closeSession();
    //Perform the action so it can be tested
    AdminMessageReposityUpdater.getInstance().handleEmployeeLoginToWard(employeeId, wardId, TimestampUtils.getTimestamp());

    //Close the session as to neutralize first-level-cache issues
    HibernateSessionFactory.closeSession();

    //Load actualSet from DAL
    Set<AgentEmployeesWards> actualSet = new HashSet<AgentEmployeesWards>(agentEmployeesWardsEngine.findByPrimaryEmployeeId(employeeId));
    actualSet.addAll(agentEmployeesWardsEngine.findByPrimaryWardId(wardId));

    //Prepare expected
    Set<AgentEmployeesWards> expectedSet = new HashSet<AgentEmployeesWards>();
    for (AgentEmployeesWards agentEmployeesWards : expectedMappingsToChangeSet){
        //We need to copy as the wardId and employeeId are properties which comprise the equals method of the class and so 
        //they cannot be changed while in a Set
        AgentEmployeesWards agentEmployeesWardsCopy = new AgentEmployeesWards(agentEmployeesWards);
        if (agentEmployeesWardsCopy.isEmployeePrimary()){
            //If this is a employee primary we want it to be updated to the new org-unit id
            agentEmployeesWardsCopy.setWardId(wardId.getValue());
        } else {
            //Otherwise we want it to be updated to the new employee id
            agentEmployeesWardsCopy.setEmployeeId(employeeId.getValue());
        }
        expectedSet.add(agentEmployeesWardsCopy);
    }
     //Assert between actualSet and expectedSet
    // Assert actual database table match expected table
   assertEquals(expectedSet, actualSet);


}
@BeforeClass
public static void setUpBeforeClass() throws SQLException,ClassNotFoundException{
    Class.forName("org.h2.Driver");
    Connection conn = DriverManager.getConnection("jdbc:h2:mem:MyCompany", "sa", "");

    ConfigurationDAO configDAO = new ConfigurationDAO();
    HibernateSessionFactory.beginTransaction();
    configDAO.attachDirty(new Configuration("All","Log", "Level", "Info",null));
    configDAO.attachDirty(new Configuration("All","Log", "console", "True",null));
    configDAO.attachDirty(new Configuration("All","Log", "File", "False",null));

    HibernateSessionFactory.commitTransaction();
    Logger log = new Logger();
    Server.getInstance().initialize(log);
    Repository.getInstance().initialize(log);
    AdminMessageReposityUpdater.getInstance().initialize(log);

    AdminEngine adminEngine = new AdminEngine();
    EmployeeEngine employeeEngine = new EmployeeEngine();
    HibernateSessionFactory.beginTransaction();
    Ward testWard = new Ward("testWard", 1, "Sales", -1, null);
    adminEngine.addWard(testWard);
    wardId = new WardId(testWard.getId());
    Ward prevWard = new Ward("prevWard", 1, "Finance", -1, null);
    adminEngine.addWard(prevWard);
    prevWardId = new WardId(prevWard.getId());

    Employee testEmployee = new Employee("testEmployee", "test", null, "employee", "f", prevWardId.getValue(), null, false, true);
    employeeEngine.setEmployee(testEmployee);
    employeeId = new EmployeeId(testEmployee.getId());

    Employee prevEmployee = new Employee("prevEmployee", "prev", null, "employee", "f", wardId.getValue(), null, false, true);
    employeeEngine.setEmployee(prevEmployee);
    prevEmployeeId = new EmployeeId(prevEmployee.getId());
    HibernateSessionFactory.commitTransaction();
    HibernateSessionFactory.closeSession();
}
@AfterClass
public static void tearDownAfterClass(){
    AdminEngine adminEngine = new AdminEngine();
    EmployeeEngine employeeEngine = new EmployeeEngine();
    HibernateSessionFactory.beginTransaction();
    employeeEngine.removeEmployeeById(employeeId);
    employeeEngine.removeEmployeeById(prevEmployeeId);
    adminEngine.removeWardById(wardId);
    adminEngine.removeWardById(prevWardId);
    HibernateSessionFactory.commitTransaction();
    HibernateSessionFactory.closeSession();
}
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2010-10-03 10:00:56

是的,这绝对是一个集成测试。使用集成测试没有任何错误,它们是测试策略的重要组成部分,但它们必须仅限于验证iif模块是否正确组装和配置是否正确设置。

如果您开始使用它们来测试功能,您将得到太多的它们,并且会发生两件非常糟糕的事情:

  1. 测试变得令人沮丧的缓慢
  2. 设计骨化集在过早的

后一个问题是因为您现在正在集成测试中耦合您的设计,即使模块本身是完全解耦的。如果你找到了一个重构的机会,它很可能会打破十几个集成测试,要么你找不到勇气,要么管理会阻止你清理(“我工作!不要碰它”综合症)。

解决方案是通过“模拟”环境编写的所有部件进行单元测试。有很好的框架可以帮助动态地制作模拟对象,我个人经常使用EasyMock。然后,YOu描述了与世界其他地方的交互,同时验证了方法的功能。

在单元测试中,现在您将得到代码所依赖的依赖项的详细描述。您还将在这里发现设计问题,因为如果在单元测试中得到复杂的模拟行为,那么就意味着存在设计问题。这是一个很好的早期反馈。

对基础结构代码进行单元测试是没有意义的,因为它可能已经过了单元测试,而且无论如何您也无能为力。

然后添加1或2个有针对性的集成测试,以验证所有部件按预期工作,查询返回正确的对象,事务被正确处理,等等.

这平衡了在组装时验证所有工作的需要,并具有重构功能,保持测试时间短,并设计松散耦合的模块。

不过,要做到这一点,还需要一些经验。我建议找一位经验丰富的开发人员,以前就这样做过,并提供饮料以换取在这一领域的指导。问很多问题。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3849263

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档