final CapFloorCMS cmsCap1 = CapFloorCMS.from(cmsCoupon1, forward1, true);
final CapFloorCMS cmsCap2 = CapFloorCMS.from(cmsCoupon2, forward2, true);
final double cmsCap1Price = methodCmsCap.presentValue(cmsCap1, SABR_MULTICURVES).getAmount(EUR);
final double cmsCap2Price = methodCmsCap.presentValue(cmsCap2, SABR_MULTICURVES).getAmount(EUR);
final EuropeanVanillaOption optionCap1 = new EuropeanVanillaOption(forward1, FIXING_TIME, true);
final NormalFunctionData dataCap1 = new NormalFunctionData(expectedRate1, 1.0, 0.0);
final double cmsCap1IV = impliedVolatility.getImpliedVolatility(dataCap1, optionCap1, cmsCap1Price / discountFactorPayment / cmsCoupon1.getNotional() / cmsCoupon1.getPaymentYearFraction());
final EuropeanVanillaOption optionCap2 = new EuropeanVanillaOption(forward2, FIXING_TIME, true);
final NormalFunctionData dataCap2 = new NormalFunctionData(expectedRate2, 1.0, 0.0);
final double cmsCap2IV = impliedVolatility.getImpliedVolatility(dataCap2, optionCap2, cmsCap2Price / discountFactorPayment / cmsCoupon2.getNotional() / cmsCoupon2.getPaymentYearFraction());
double spreadVol = cmsCap1IV * cmsCap1IV - 2 * correlation * cmsCap1IV * cmsCap2IV + cmsCap2IV * cmsCap2IV;
spreadVol = Math.sqrt(spreadVol);
final EuropeanVanillaOption optionSpread = new EuropeanVanillaOption(STRIKE, FIXING_TIME, IS_CAP);
final NormalFunctionData dataSpread = new NormalFunctionData(expectedRate1 - expectedRate2, 1.0, spreadVol);
final Function1D<NormalFunctionData, Double> priceFunction = normalPrice.getPriceFunction(optionSpread);
final double cmsSpreadPriceExpected = discountFactorPayment * priceFunction.evaluate(dataSpread) * CMS_CAP_SPREAD.getNotional() * CMS_CAP_SPREAD.getPaymentYearFraction();
assertEquals("CMS spread: price with constant correlation", cmsSpreadPriceExpected, cmsSpreadPrice, TOLERANCE_PV);
}