我有Thread
,它在程序运行时运行并轮询队列,检查它是否有对象,如果有,则调用对象上的方法
这是代码:
while(isRunning){
synchronized (loginQueue) {
if(loginQueue.peek() != null) {
Object[] loginObjectWithConnection = loginQueue.poll();
tryLogin(loginObjectWithConnection);
}
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
这是tryLogin方法
private void tryLogin(Object[] loginObjectWithConnection) {
LoginPacket packet = (LoginPacket)loginObjectWithConnection[0];
Connection connection = (Connection)loginObjectWithConnection[1];
try {
if(playerDataService.arevalidCredentials(packet.getUserName(), packet.getPassword())) {
if(!playerDataService.isPlayerBanned(packet.getUserName())){ //Player exists in the system
communicationService.sendTCP(connection, packetFactory.makeLoginFailurePacket(StringConstants.PLAYER_BANNED));
} else{ //Player is not banned
}
} else { // Player does not exist
communicationService.sendTCP(connection, packetFactory.makeLoginFailurePacket(StringConstants.INVALID_USER));
}
} catch (SQLException e) {
communicationService.sendTCP(connection, packetFactory.makeLoginFailurePacket(StringConstants.SERVER_ERROR));
e.printStackTrace();
}
}
现在我的问题是,我想测试这些服务方法的调用,但当我运行单元测试时,它们不起作用,因为达到tryLogin的点需要时间,在此之前JUnit会失败。我尝试使用Thread.sleep()
,但我知道这不是正确的方法,因为它有时失败,有时通过。
这是我的单元测试
@Test
public void theExpectedMessageShouldBeSentIfUserIsBanned() throws InterruptedException, SQLException {
//Arrange
when(moqLoginQueue.peek()).thenReturn(object);
when(moqLoginQueue.poll()).thenReturn(object);
LoginFailurePacket packet = new LoginFailurePacket(StringConstants.PLAYER_BANNED);
when(moqPacketFactory.makeLoginFailurePacket(StringConstants.PLAYER_BANNED)).thenReturn(packet);
when(moqPlayerDataService.arevalidCredentials(anyString(), anyString())).thenReturn(true);
when(moqPlayerDataService.isPlayerBanned(anyString())).thenReturn(true);
//Act
loginManager.start();
Thread.sleep(10); //Dirty hack -.-
//Assert
verify(moqCommunicationService).sendTCP(any(Connection.class), eq(packet));
}
系统在当前形式下是不稳定的:在良好的测试质量中有:
- 其他程序员很容易理解
- 其他程序员很难突破
- 运行速度快
要测试的逻辑是LoginManager.tryLogin
,它在您的代码段中是私有的。如果你想公开记录它(测试是一种文档:它们说明系统应该如何运行),它必须是公开的。
我建议将所有这些逻辑转移到一个新类中的方法:Authentication.attempt()
(我建议使用一个不可变的对象和一个不接受任何参数的方法——有人说OO设计中的最佳参数数为零)。
既然测试是可行的,我还认为你应该去掉LoginManager.start()
中的所有代码:只需使用ExecutorService
并提交身份验证尝试——这样你就有了更快的程序和更少的代码来测试,因为困难(和棘手)的部分是由Java管理的。