0

Javaアプリの単体テストを作成していますが、スローされる可能性のあるJiBX例外のテストを作成する必要があります。私がテストしているメソッドは、JiBX例外がスローされる可能性がある別のクラスのメソッドを呼び出します。これは私がテストしているクラスです(クラスAと呼びましょう):

@Inject
private CommonDAL commonDAL;

@Async
public Future<String> getTransactionalXXXAvailability(
        List<XXXAvailRequestEntry> requestEntries, TravelWindow travelWindow) {
    if (requestEntries.size() == 0)
        return null;
    XXXAvailRqAccessor requestAccessor = new XXXAvailRequestBuilder().buildRequest(requestEntries, travelWindow);
    logger.info(requestAccessor.marshalRequest());
    String responseAsXml = null;
    try {
        responseAsXml = getResponse(requestAccessor.getRequest());
    } catch (JiBXException e) {
        logger.error("Problem unmarshaling the XXX avail response: ", e);
    }

    logger.info(responseAsXml);
    return new AsyncResult<String>(responseAsXml);
}

private String getResponse(OTAXXXAvailRQ request) throws JiBXException {
    HbsiConnectionInfo connectionInfo = new HbsiConnectionInfo();
    connectionInfo.useConnectionInfoFromContext();

    HBSIXML4OTAWebserviceSoap hbsiSoap = getHbsiSoapService(connectionInfo);

    InterfacePayload header = new InterfacePayload();
    header.setChannelIdentifierId("XXXXXXXXX");
    header.setVersion("2005B");
    header.setInterface("HBSI XML 4 OTA");

    ComponentInfo componentInfo = new ComponentInfo();
    XXXAvailRqAccessor requestAccessor = new XXXAvailRqAccessor(request);
    componentInfo.setId(requestAccessor.getFirstXXXCode());
    componentInfo.setUser( connectionInfo.getUsername() );
    componentInfo.setPwd( connectionInfo.getPassword() );
    componentInfo.setComponentType(EComponentType.XXX);

    Login login = new Login();
    login.setComponentInfo(componentInfo);

    Message body = new Message();
    // todo: this needs to be unique for every request.
    // todo: hook up to logging
    body.setRequestId(UUID.randomUUID().toString());
    body.setTransaction(ETransaction.XXX_AVAIL_RQ);

    body.setXML(requestAccessor.marshalRequest());

    return hbsiSoap.getSoapRequest(header, body, login);
}

HBSIXML4OTAWebserviceSoap getHbsiSoapService(HbsiConnectionInfo connectionInfo) {
    HBSIXML4OTAWebservice ws = new HBSIXML4OTAWebservice( connectionInfo.getWsdlLocation() );

    HBSIXML4OTAWebserviceSoap hbsiSoap = ws.getHBSIXML4OTAWebserviceSoap();
    Map<String, Object> requestContext = ((BindingProvider)hbsiSoap).getRequestContext();
    String readTimeout = commonDAL.getPropertyValue(new PropertyKey(Section.HBSI,
            Property.HBSI_WS_READ_TIMEOUT));
    requestContext.put(BindingProviderProperties.REQUEST_TIMEOUT, Integer.parseInt(readTimeout));
    String connectionTimeout = commonDAL.getPropertyValue(new PropertyKey(Section.HBSI,
            Property.HBSI_WS_CONNECTION_TIMEOUT));
    requestContext.put(BindingProviderProperties.CONNECT_TIMEOUT, Integer.parseInt(connectionTimeout));
    return hbsiSoap;
}

エラーをスローするメソッドは次のとおりです(別のクラスから、クラスBと呼びましょう)。

public String marshalRequest() {
    StringWriter requestAsXml = new StringWriter();

    try {
        IBindingFactory bindingFactory = BindingDirectory.getFactory(PROTECTEDCLASSNAME.class);
        IMarshallingContext marshalingContext = bindingFactory.createMarshallingContext();
        marshalingContext.setIndent(2);
        marshalingContext.setOutput(requestAsXml);
        marshalingContext.marshalDocument(request);

    } catch (JiBXException e) {
        logger.error("Problem marshaling PROTECTEDCLASSNAME.", e);
    }

    return requestAsXml.toString();
}

「body.setXML(requestAccessor.marshalRequest());」の場合 が呼び出され、テストによって別のクラス(requestAccessor)が訪問され、そのメソッド.marshalRequestは、JiBX例外がスローされることになっている場所です。私が書いているテストの目的は、このクラスAの単体テストカバレッジを100&にすることですが、requestAccessorというXXXAvailRqAccessorオブジェクトをモックできないため、テスト対象のシステムは少なくとも2つのクラスで構成されています。次の理由により、このエラーを生成するためのテストを取得できません。

  • requestAccessorというXXXAvailRqAccessorオブジェクトは、テストしているメソッド内でインスタンス化されるため、モックを使用して例外をスローすることはできません。

  • .getResponse()に渡されたOTAXXXAvailRQ引数は、XXXAvailRqAccessorのビルダーによって作成されているため、モックできません。

  • IBindingFactoryをスパイしようとしましたが、機能しませんでした。IBindingFactoryをインスタンス化してスパイできるようにするメソッドをクラスBで作成しましたが、それは機能しませんでした。

  • また、PowerMockを使用して、インスタンス化されたときにモックXXXAvailRqAccessorを返そうとしましたが、.getRequestのJiBXExceptioinをモックしようとすると、Mockitoは「チェックされた例外はこのメソッドに対して無効です」と言いました。Mockitoにこのエラーをスローさせることができない場合、関連するオブジェクトを操作してスローすることが可能かどうかわかりません。

4

2 に答える 2

2

そうではないか、少なくともそのような方法はわかりません。あなたが本当にそれをしたいのであれば(私はそれに反対です)、そのクラスでこのようなメソッドを作成することができます:

IBindingFactory getBindingFactory() {
    return BindingDirectory.getFactory(PROTECTEDCLASSNAME.class);
}

そして、この行を置き換えます:

IBindingFactory bindingFactory = BindingDirectory.getFactory(PROTECTEDCLASSNAME.class);

と:

IBindingFactory bindingFactory = getBindingFactory();

次に、このオブジェクトをspy()(慣れていない場合は、ドキュメントのMockito.spy()で読むことができます)して、このメソッドにモックを返すようにすることができます。その時点から、それはスムーズな航海です。

ただし、このアプローチはお勧めできません。理由は次のとおりです。

  1. テストのためだけに新しいメソッド(役に立たないメソッド)を作成しています
  2. 上記のメソッドはテスト用に表示する必要があるため、プライベートとしてマークすることはできません...
  3. 私は一般的にスパイの大ファンではありません

問題は残っています:そのようなケースを適切にテストする方法。ほとんどの場合、私は可能な限りリファクタリングを試みますが、それが役立つ場合もあります。そして他の場合...まあ、私はまだより良い解決策を思いつきませんでした。

于 2012-08-07T13:09:00.717 に答える
1

コメントで述べたように、私はマテウスの解決策を全面的に支持しています。しかし、別の方法があります。メソッドを持つクラスにmarshalRequest、タイプのプライベートfinalフィールドがありIBindingFactoryます。また、このクラスには、追加の引数が1つあるpackage-privateコンストラクター(つまり、IBindingFactoryto set)があります。通常のコンストラクターはBindingDirectory.getFactory( ... )、新しいコンストラクターを呼び出してから呼び出します。したがって、標準コンストラクターに単一のString引数がある場合、クラスは次のようになります。

public class MyClass{
    private String name;
    private IBindingFactory bindingFactory;

    public MyClass(String name){
        this(name, BindingDirectory.getFactory(PROTECTEDCLASSNAME.class));
    }

    MyClass(String name, IBindingFactory bindingFactory){
        this.name = name;
        this.bindingFactory = bindingFactory;
    }

    public String marshalRequest() {
        StringWriter requestAsXml = new StringWriter();

        try {
            IMarshallingContext marshalingContext = bindingFactory.createMarshallingContext();
            marshalingContext.setIndent(2);
            marshalingContext.setOutput(requestAsXml);
            marshalingContext.marshalDocument(request);

        } catch (JiBXException e) {
            logger.error("Problem marshaling PROTECTEDCLASSNAME.", e);
        }

        return requestAsXml.toString();
    }
}

これを行う理由は、クラスのテストでモックを作成し、IBindingFactoryそれをpackage-privateコンストラクターに渡すことができるようにするためです。

于 2012-08-08T11:15:27.367 に答える