Search code examples
javajunitjmock

How to inject values into a mocked object's constructor or via a setter? Am getting Unexpected Invocation error


My question: how to create a mocked object and inject attributes via the constructor or a setter?

I get unexpected invocation errors. I am doing a set on my mock object in @Before to set the name attribute for my BAPI. When i execute the test, I get an unexpected invocation error on my setName method. But, I don't really want to test this method. I'm just plugging it so the value is there when my code executes the method checkParm(b).

If I don't add any expectation for the setter on the mocked I get unexpected invocation. But, also if I add this code to the expectations, I still get unexpected invocation.

        ignoring(mockAdapter).setName(BAPI_NAME);
        inSequence(sequence);

here's my @Before method

@Before
public void setUp() throws Exception {

    objectUnderTest = new ApoSAPExtractor();

    mockAdapter = context.mock(BapiAdapter.class);
    mockAdapter.setName(BAPI_NAME);

    apoResults = new ApoResults();
    apoParameterBean = new ApoParameterBean();
}

Then my test method:

@Test
public final void testExtract() throws Exception {

    final Sequence sequence = context.sequence(SEQUENCE);

    context.checking(new Expectations() {{

        atLeast(1).of(mockAdapter).getName();
        will(returnValue(new String())); 
        inSequence(sequence);

        oneOf(mockAdapter).activate();
        inSequence(sequence);

        oneOf(mockAdapter).getImportTableParameter(IM_PARMS);
        inSequence(sequence);
        will(returnValue(JCoTable.class)); 

        oneOf(mockAdapter).execute(); 
        inSequence(sequence);

        oneOf(mockAdapter).getExportTableAdapter(EX_PO_APO); 
        inSequence(sequence);
        will(returnValue(new TableAdapter(with(any(JCoTable.class)))));

    }});

    objectUnderTest.extract(mockAdapter, apoParameterBean);     
    context.assertIsSatisfied();

}

The class I'm mocking:

     public class ApoSAPExtractor implements SAPExtractor<ApoResults, ApoParameterBean> {

private final static Logger logger = Logger.getLogger(ApoSAPExtractor.class);

public List<ApoResults> extract(BapiAdapter b, ApoParameterBean pb) throws JCoException, Exception {

    checkParm(b);

    List<ApoResults>list = new ArrayList<ApoResults>();
    try {
        b.activate();

        JCoTable itp = b.getImportTableParameter(APOConstants.BAPI_IM_PARMS);
        itp.appendRow();

        JCoTable t = itp.getTable(APOConstants.BAPI_DOC_TYPES);
        Utils.appendParm(t, pb.getDocTypes());

        b.execute();

        TableAdapter ta = b.getExportTableAdapter(APOConstants.BAPI_EX_PO_APO);

        for (int i = 0; i < ta.size(); i++) {

            ApoResults ar = new ApoResults();

            ... lots of setters ...

            list.add(ar);

            ta.next();
        }

    } catch (Exception e) {
        logger.info(String.format("Program %s failed.",this.getClass().getSimpleName(),  "failed"));
        e.printStackTrace();
        throw e;
    }

    return list;
}

Solution

  • You can't inject things into a mock, you can set expectations on it

    Instead of this (which gives you your unexpected exception):

    mockAdapter.setName(BAPI_NAME);
    

    you might do this in your expectations:

    atLeast(1).of(mockAdapter).getName();
    will(returnValue(BAPI_NAME));