我在Spring MVC应用程序中的单元测试遇到了一些麻烦。在完全公开的情况下,由于缺乏从头开始编写测试套件的经验,我很有可能错误地设计我的单元测试。
我目前设计的方式是测试用户服务,测试套件使用原始SQL语句来验证数据是否正确插入/检索/更新。我遇到的问题是,在执行frist预处理语句之后,后续语句会挂起execute()
方法。测试结果最终为“超出锁定等待超时;尝试重新启动事务”
根据我在网上看到的内容,这可能是一个交易管理问题,有人没有发布锁定,但我不确定如何最好地做到这一点,甚至不知道在哪里做。
下面是一些相关代码,如果需要更多代码,请告诉我。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"/applicationContext-base.xml", "/application-security.xml"})
@TransactionConfiguration(transactionManager="txManager")
@Transactional
public class TestUserService {
@Autowired
UsersService userService;
@Autowired
DataSource dataSource;
Connection connection;
@Before
public void setup() throws Exception{
connection = dataSource.getConnection();
}
@Test
public void testCreateUser() throws Exception{
Collection<GrantedAuthorityImpl> auths = new ArrayList<GrantedAuthorityImpl>();
auths.add(new GrantedAuthorityImpl(SecurityConstants.ROLE_USER));
User user = new User("testUser", "testpassword", true, true, true, true, auths, "salt");
User tmp = userService.createUser(user);
PreparedStatement ps = connection.prepareStatement("select id, username, password, created, enabled, salt from users where id = ?");
PreparedStatement ps2 = connection.prepareStatement("select user, authority from user_authorities where user = ?");
ps.setLong(1, tmp.getId());
ps2.setLong(1, tmp.getId());
ResultSet rs = ps.executeQuery();
ResultSet rs2 = ps2.executeQuery();
rs.first();
rs2.first();
Collection<GrantedAuthorityImpl> authsFromDb = new ArrayList<GrantedAuthorityImpl>();
rs.first();
do{
authsFromDb.add(new GrantedAuthorityImpl(rs2.getString("authority")));
}while(rs2.next());
User tmp2 = new User(rs.getString("username"), rs.getString("password"), rs.getBoolean("enabled"), true, true, true, authsFromDb, rs.getString("salt"));
Assert.assertEquals(tmp.getUsername(), tmp2.getUsername());
Assert.assertEquals(tmp.getId(), tmp2.getId());
Assert.assertEquals(tmp.getPassword(), tmp2.getPassword());
Assert.assertEquals(tmp.getSalt(), tmp2.getSalt());
Assert.assertEquals(tmp.getAuthorities(), tmp2.getAuthorities());
Assert.assertEquals(tmp.isEnabled(), tmp2.isEnabled());
}
@Test
public void testSaveUser() throws Exception{
long createdTime = System.currentTimeMillis();
String insertionQry = "insert into users (username, password, created, enabled, salt) values ('chris', 'somepassword'," + createdTime + ",1,'salt')";
PreparedStatement ps = connection.prepareStatement(insertionQry, Statement.RETURN_GENERATED_KEYS);
ps.execute();
ResultSet rs = ps.getGeneratedKeys();
rs.first();
long id = rs.getLong(1);
Assert.assertEquals(true, id != 0);
String loadQry = "select id, username, password, created, enabled, salt from users where id = " + id;
ps = connection.prepareStatement(loadQry);
rs = ps.executeQuery();
rs.first();
Assert.assertEquals(rs.getString("username"), "chris");
Assert.assertEquals(rs.getString("password"), "somepassword");
Assert.assertEquals(rs.getBoolean("enabled"), true);
Assert.assertEquals(rs.getString("salt"), "salt");
User user = new User("second_username", "newpassword", false, true, true, true, AuthorityUtils.NO_AUTHORITIES, "secondsalt");
user.setId(rs.getLong("id"));
userService.saveUser(user);
ps = connection.prepareStatement(loadQry);
rs = ps.executeQuery();
rs.first();
Assert.assertEquals(rs.getString("username"), "second_username");
Assert.assertEquals(rs.getString("password"), "newpassword");
Assert.assertEquals(rs.getBoolean("enabled"), false);
Assert.assertEquals(rs.getString("salt"), "secondsalt");
}
答案 0 :(得分:3)
为了在Spring事务管理中使用原始JDBC Connection
,您需要将其作为DataSourceUtils.getConnection(dataSource)
获取,请参阅DataSourceTransactionManagement
。也许这就是原因。
因此,问题是通过Connection
获得并在测试代码中使用的dataSource.getConnection()
与正在测试的代码中使用的Spring管理的连接不同。因此,在这些连接中执行的查询属于不同的事务,并且在单个线程的许多事务中执行查询通常会导致死锁。
使用DataSourceUtils
时,您将获得与正在测试的代码相同的Spring管理连接,以便您在一次交易中执行所有查询。
答案 1 :(得分:0)
我发现您的测试有几个问题: