在引发异常后验证 Spock 模拟异步交互



>我正在尝试使用阻塞变量来验证协作者方法失败后的异步交互。 这就是我得到的:

public class ServiceAImpl {
private final ServiceB serviceB;
private final ServiceC serviceC;
@Override
public void createAccount(String userId) {
try {
serviceB.createUserAccount(userId);
} catch (Exception e) {
asyncSaveCreationError(e);
throw e;
}
}
private void asyncSaveCreationError(Exception e) {
runAsync(() -> saveCreationError(e));
}
private void saveCreationError(Exception e) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
serviceC.save(pw.toString());
}
}
class ServiceAImplTest extends Specification {
def serviceB = Mock(ServiceB)
def serviceC = Mock(ServiceC)
@Subject
def subject = new ServiceAImpl(serviceB, serviceC)
def "createAccount - should throw Exception and save error"() {
given:
def result = new BlockingVariable<Boolean>(10)
when:
subject.createAccount("userId")
then:
1 * serviceB.createUserAccount(_) >> { throw new Exception() }
thrown(Exception)
1 * serviceC.save(_) >> { result.set(true) }
result.get()
0 * _
}
}

抛出异常,但从未设置阻塞变量,因此我收到以下错误:

BlockingVariable.get() timed out after 10.00 seconds
at spock.util.concurrent.BlockingVariable.get(BlockingVariable.java:113)*

我尝试使用普通的 Thread.sleep 但总是无法与serviceC.save

交互

破坏你代码的事情是,模拟交互是每个then块中首先评估的东西,即使你首先列出其他东西。因此,要使其正常工作,您需要使用第二个then块,如文档中的章节调用顺序中所述。由于首先评估模拟,因此执行甚至没有达到等待足够长的时间以便可以触发保存交互的result.get()

这应该可以解决您的问题:

class ServiceAImplTest extends Specification {
ServiceB serviceB = Mock()
ServiceC serviceC = Mock()
@Subject
def subject = new ServiceAImpl(serviceB, serviceC)
def "createAccount - should throw Exception and save error"() {
given:
def result = new BlockingVariable<Boolean>(10.0)

when:
subject.createAccount("userId")

then: 'first catch the exception and wait for the result'
thrown(Exception)
result.get()

then: 'verify mock interactions'
1 * serviceB.createUserAccount(_) >> { throw new Exception() }
1 * serviceC.save(_) >> { result.set(true) }
0 * _
}
}

您可以在 Groovy Web 控制台上测试 MCVE

最新更新