Unit testing 模拟OutputStream时发生Grails GMock错误

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的几乎所有内容都很少有文档记录 测试中的方法:我正在使用示例,并稍微扩展了一下,以满足我的需要。我接收用于连接的凭据

我花了很长时间试图建立并运行一个模拟框架来测试我的SFTP服务。我对EasyMock、PowerMock和JMockit很熟悉,但最终选择了GMock<代码>测试('org.gmock:gmock:0.8.2'){排除'junit'}

现在我已经成功运行了happy path测试,我正在编写重试逻辑和失败场景。我现在遇到两个问题。我似乎找不到解决这些问题的方法,因为Grails和GMock的几乎所有内容都很少有文档记录

测试中的方法:我正在使用示例,并稍微扩展了一下,以满足我的需要。我接收用于连接的凭据和文件名。我创建一个FileOutputStream,然后连接到SFTP服务器。如果我得到一个异常,那么我将重试第n次(为了方便起见,这里进行了简化)

错误1:然后我做了一个简单的复制/粘贴,除了测试方法名称之外,什么都没有更改,我得到了以下错误:

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
}