Unit testing 模拟OutputStream时发生Grails GMock错误
我花了很长时间试图建立并运行一个模拟框架来测试我的SFTP服务。我对EasyMock、PowerMock和JMockit很熟悉,但最终选择了GMock<代码>测试('org.gmock:gmock:0.8.2'){排除'junit'} 现在我已经成功运行了happy path测试,我正在编写重试逻辑和失败场景。我现在遇到两个问题。我似乎找不到解决这些问题的方法,因为Grails和GMock的几乎所有内容都很少有文档记录 测试中的方法:我正在使用示例,并稍微扩展了一下,以满足我的需要。我接收用于连接的凭据和文件名。我创建一个FileOutputStream,然后连接到SFTP服务器。如果我得到一个异常,那么我将重试第n次(为了方便起见,这里进行了简化) 错误1:然后我做了一个简单的复制/粘贴,除了测试方法名称之外,什么都没有更改,我得到了以下错误:Unit testing 模拟OutputStream时发生Grails GMock错误,unit-testing,grails-2.0,gmock,Unit Testing,Grails 2.0,Gmock,我花了很长时间试图建立并运行一个模拟框架来测试我的SFTP服务。我对EasyMock、PowerMock和JMockit很熟悉,但最终选择了GMock测试('org.gmock:gmock:0.8.2'){排除'junit'} 现在我已经成功运行了happy path测试,我正在编写重试逻辑和失败场景。我现在遇到两个问题。我似乎找不到解决这些问题的方法,因为Grails和GMock的几乎所有内容都很少有文档记录 测试中的方法:我正在使用示例,并稍微扩展了一下,以满足我的需要。我接收用于连接的凭据
java.lang.StackOverflowError
at java.lang.ref.SoftReference.get(SoftReference.java:93)
at org.codehaus.groovy.util.ManagedReference.get(ManagedReference.java:41)
at org.codehaus.groovy.util.ManagedConcurrentMap$Entry.isEqual(ManagedConcurrentMap.java:62)
at org.codehaus.groovy.util.AbstractConcurrentMap$Segment.getOrPut(AbstractConcurrentMap.java:91)
at org.codehaus.groovy.util.AbstractConcurrentMap.getOrPut(AbstractConcurrentMap.java:35)
at org.codehaus.groovy.reflection.ClassInfo.getClassInfo(ClassInfo.java:103)
at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.getMetaClass(MetaClassRegistryImpl.java:227)
at org.codehaus.groovy.runtime.InvokerHelper.getMetaClass(InvokerHelper.java:751)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.createCallStaticSite(CallSiteArray.java:59)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.createCallSite(CallSiteArray.java:146)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
at org.codehaus.groovy.runtime.callsite.StaticMetaClassSite.call(StaticMetaClassSite.java:55)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
at org.codehaus.groovy.runtime.callsite.StaticMetaClassSite.call(StaticMetaClassSite.java:55)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
at org.codehaus.groovy.runtime.callsite.StaticMetaClassSite.call(StaticMetaClassSite.java:55)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
这会持续一段时间
错误2:然后我决定注释掉happy path并执行重试场景。所以我尝试在任何地方使用.times(2),但它不喜欢构造函数上的.times(2)。如果我不这样做,它就会抱怨,因为构造函数会被调用两次,因为重试会关闭所有内容,然后在重试时重新实例化它
然后,我尝试创建了两个所有的模拟,直到失败,在构建第二个FileOutputStream模拟的过程中抛出了某种NPE。它似乎在对文件进行比较
public void testSavingRemoteToLocal_RetryOnce() throws JSchException {
// Holders for testing
String fileToTransfer = 'test_large_file_desktop.txt'
FtpCredential localCredential = new FtpCredential()
// populate credential
FtpCredential remoteCredential = new FtpCredential()
// populate credential
// Mocks
// First loop that fails
File mockFile2 = mock(File, constructor(inputCredential.remoteBaseDir, fileToTransfer))
mockFile2.exists().returns(false)
FileOutputStream mockFIO2 = mock(FileOutputStream, constructor(mockFile2, false))
// connection
JSch mockJSch2 = mock(JSch, constructor())
Session mockSession2 = mock(Session)
mockJSch2.getSession(outputCredential.username, outputCredential.server, outputCredential.port).returns(mockSession2)
mockSession2.setConfig ("StrictHostKeyChecking", "no")
mockSession2.password.set(outputCredential.password)
mockSession2.connect().raises(new SftpException(0, "throw an exception to retry"))
mockSession2.disconnect()
mockFIO2.close()
// second loop that passes
File mockFile = mock(File, constructor(inputCredential.remoteBaseDir, fileToTransfer))
mockFile.exists().returns(false)
FileOutputStream mockFIO = mock(FileOutputStream, constructor(mockFile, true)) // <-- Fails here with a NPE in mockFile.compareTo
// connection
JSch mockJSch = mock(JSch, constructor())
Session mockSession = mock(Session)
ChannelSftp mockChannel = mock(ChannelSftp)
mockJSch.getSession(outputCredential.username, outputCredential.server, outputCredential.port).returns(mockSession)
mockSession.setConfig ("StrictHostKeyChecking", "no")
mockSession.password.set(outputCredential.password)
mockSession.connect()
mockSession.openChannel("sftp").returns(mockChannel)
mockChannel.connect()
mockChannel.cd(outputCredential.remoteBaseDir)
// transfer
mockChannel.get (fileToTransfer, mockFIO, FtpMonitor.getInstance(assetId), ChannelSftp.RESUME, 0)
// finally method mocks
mockChannel.exit()
mockSession.disconnect()
mockFIO.close()
// Test execution
play {
service.sleepDuration = 200
service.sftpCopyFrom(outputCredential, inputCredential, fileToTransfer, assetId )
}
// Assert the results
}
public void testSavingRemoteToLocal_RetryOnce()抛出JSCHEException{
//测试用支架
字符串fileToTransfer='test\u large\u file\u desktop.txt'
FtpCredential localCredential=新的FtpCredential()
//填充凭证
FtpCredential remoteCredential=新的FtpCredential()
//填充凭证
//嘲弄
//失败的第一个循环
File mockFile2=mock(文件,构造函数(inputCredential.remoteBaseDir,fileToTransfer))
mockFile2.exists().返回(false)
FileOutputStream mockFIO2=mock(FileOutputStream,构造函数(mockFile2,false))
//联系
JSch mockJSch2=mock(JSch,constructor())
会话模拟会话2=模拟(会话)
mockJSch2.getSession(outputCredential.username、outputCredential.server、outputCredential.port)。返回(mockSession2)
mockSession2.setConfig(“StrictHostKeyChecking”,“否”)
mockSession2.password.set(outputCredential.password)
mockSession2.connect()引发(新的SftpException(0,“抛出异常以重试”))
mockSession2.disconnect()
mockFIO2.close()
//通过的第二个循环
File mockFile=mock(文件,构造函数(inputCredential.remoteBaseDir,fileToTransfer))
mockFile.exists().returns(false)
FileOutputStream mockFIO=mock(FileOutputStream,constructor(mockFile,true))/您尝试过Gmock 0.8.3吗?我记得我已经修复了一些与此相关的错误。我确实发现,如果我有新文件(…),至少可以让失败场景正常工作
在循环之外。但是如果文件部分传输,这会影响我的重试逻辑吗?我需要获取文件的当前长度,并且我不想在线程休眠时将文件保留在内存中。我现在可以同时运行我的快乐路径和重试测试。我不再得到StackOverflow错误;但是,我在运行时仍然得到NPE在循环中声明/实例化文件。当FileOutputStream使用file对象构造时会发生这种情况。我不想在重试逻辑之外声明文件,因为线程处于休眠状态,我不想在重试处于休眠状态时保留文件。我甚至不知道为什么它不使用模拟FOS构造函数。Altho呃,我不能让一切都正常工作,这确实让我更亲近了。最后他们放弃了JUnit。我不同意这一点,但有时客户在做这件事的时候没有意识到一种不好的做法。
java.lang.StackOverflowError
at java.lang.ref.SoftReference.get(SoftReference.java:93)
at org.codehaus.groovy.util.ManagedReference.get(ManagedReference.java:41)
at org.codehaus.groovy.util.ManagedConcurrentMap$Entry.isEqual(ManagedConcurrentMap.java:62)
at org.codehaus.groovy.util.AbstractConcurrentMap$Segment.getOrPut(AbstractConcurrentMap.java:91)
at org.codehaus.groovy.util.AbstractConcurrentMap.getOrPut(AbstractConcurrentMap.java:35)
at org.codehaus.groovy.reflection.ClassInfo.getClassInfo(ClassInfo.java:103)
at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.getMetaClass(MetaClassRegistryImpl.java:227)
at org.codehaus.groovy.runtime.InvokerHelper.getMetaClass(InvokerHelper.java:751)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.createCallStaticSite(CallSiteArray.java:59)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.createCallSite(CallSiteArray.java:146)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
at org.codehaus.groovy.runtime.callsite.StaticMetaClassSite.call(StaticMetaClassSite.java:55)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
at org.codehaus.groovy.runtime.callsite.StaticMetaClassSite.call(StaticMetaClassSite.java:55)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
at org.codehaus.groovy.runtime.callsite.StaticMetaClassSite.call(StaticMetaClassSite.java:55)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
public void testSavingRemoteToLocal_RetryOnce() throws JSchException {
// Holders for testing
String fileToTransfer = 'test_large_file_desktop.txt'
FtpCredential localCredential = new FtpCredential()
// populate credential
FtpCredential remoteCredential = new FtpCredential()
// populate credential
// Mocks
// First loop that fails
File mockFile2 = mock(File, constructor(inputCredential.remoteBaseDir, fileToTransfer))
mockFile2.exists().returns(false)
FileOutputStream mockFIO2 = mock(FileOutputStream, constructor(mockFile2, false))
// connection
JSch mockJSch2 = mock(JSch, constructor())
Session mockSession2 = mock(Session)
mockJSch2.getSession(outputCredential.username, outputCredential.server, outputCredential.port).returns(mockSession2)
mockSession2.setConfig ("StrictHostKeyChecking", "no")
mockSession2.password.set(outputCredential.password)
mockSession2.connect().raises(new SftpException(0, "throw an exception to retry"))
mockSession2.disconnect()
mockFIO2.close()
// second loop that passes
File mockFile = mock(File, constructor(inputCredential.remoteBaseDir, fileToTransfer))
mockFile.exists().returns(false)
FileOutputStream mockFIO = mock(FileOutputStream, constructor(mockFile, true)) // <-- Fails here with a NPE in mockFile.compareTo
// connection
JSch mockJSch = mock(JSch, constructor())
Session mockSession = mock(Session)
ChannelSftp mockChannel = mock(ChannelSftp)
mockJSch.getSession(outputCredential.username, outputCredential.server, outputCredential.port).returns(mockSession)
mockSession.setConfig ("StrictHostKeyChecking", "no")
mockSession.password.set(outputCredential.password)
mockSession.connect()
mockSession.openChannel("sftp").returns(mockChannel)
mockChannel.connect()
mockChannel.cd(outputCredential.remoteBaseDir)
// transfer
mockChannel.get (fileToTransfer, mockFIO, FtpMonitor.getInstance(assetId), ChannelSftp.RESUME, 0)
// finally method mocks
mockChannel.exit()
mockSession.disconnect()
mockFIO.close()
// Test execution
play {
service.sleepDuration = 200
service.sftpCopyFrom(outputCredential, inputCredential, fileToTransfer, assetId )
}
// Assert the results
}