Я написал свой первый юнит-тест и думаю, что он слишком зависит от других модулей, и я не уверен, так ли это, потому что:
- Это сложный тест
- Я на самом деле написал интеграционный тест или
- У меня проблема с дизайном
Сначала я скажу, что, хотя у меня есть около 4 лет опыта разработки, я никогда не учился и не обучался автоматическому тестированию.
Я только что закончил серьезное изменение в нашей реализации DAL с Hibernate, и мой коллега предложил мне написать юнит-тесты для новых деталей.
Основное изменение касалось переключения на шаблон «Сессия-на-запрос» и более конструктивного использования транзакций приложения.
Из-за характера вышеуказанного изменения модульное тестирование начинается в точке, когда поступает конкретный запрос и начинает транзакцию, а тест заканчивается после завершения транзакции и проверяет, выполнила ли транзакция изменения, которые она должна была сделать.
Этот тест включает в себя инициализацию следующих объектов:
- БД в памяти - так что будут данные для работы.
- Инициализировать регистратор компании - так как метод зависит от него.
- Инициализируйте репозиторий, сконструированный как одноэлементный - это ворота функции в DAL, но он также хранит другие вещи, так что это большой объект для создания.
- Инициализировать обработчик запросов, который также является одноэлементным - здесь содержится метод, который нужно протестировать.
Я думаю, что на самом деле я написал интеграционный тест, так как мне нужно инициализировать БД, Hibernate и репозиторий, но я не уверен, как мог бы написать его иначе, учитывая обстоятельства, когда в тестируемом методе используются все эти объекты для его действия, и мне интересно посмотреть, как выполняется обработка транзакций (что делается на проверенном методе).
Буду признателен за все комментарии и мысли и с удовольствием разработаю или проясню все, если они недостаточно ясны.
Спасибо
Итай
P.S. HibernateSessionFactory
фактически является широко известным HibernateUtil
из книги Hibernate In Action
, ошибочно названным по историческим причинам.
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();
}
}