开发者

Testing an async method call

Below is a simplified setup of my application. It has a class Foobar which calls on a facade method for fetching data. The facade then calls on a web service to actually get the data and then manipulates the data a bit and then returns it to Foobar.

Now because the web service might take a good while to run, the method call to the facade needs to be asynchronous. Hence the facade's method doesn't have a return value, but instead, the method uses a callback object. Look at the example and continue reading below.

public class Foobar {
    private List<DTO> dtos;

    @Autowired
    private Facade facade;

    public开发者_运维问答 void refresh() {
        facade.refreshFoobar(new CallBack() {
            public void dataFetched(List<DTO> dtos) {
                setDtos(dtos);
            }

        });
    }    

    public void setDtos(List<DTO> dtos) {
        this.dtos = dtos;
    }
}


public class Facade {

    ...

    public void refreshFoorbar(CallBack cb) {
        // Fetch data from a web service
        List<DTO> dtos = webService.getData();  
        // Manipulate DTOs
        ....
        // call on the callback method
        cb.dataFecthed(dtos);
    }

}

I have two ways of making the facade's method asynchronous, either by creating a thread manually or by using springs @Async annotation.

public class Facade {

    public void refreshFoorbar(CallBack cb) {
        new Thread() {

            @Override
            public void run() {
                ....
            }

        }.start();

    }
}

// ... OR ...

public class Facade {

    @Async
    public void refreshFoorbar(CallBack cb) {
        ....    
    }
}

My problem is that I now need to write an integration test for this chain of method calls. I think I need to force the async facade call to be synchronous when the integration test is ran, otherwise I won't know for sure when I can do the appropriate asserts. The only idea for making the method call synchronous is to use manually handled threads AND making the threading conditional (so, for testing purposes, I have an if clause which determines if the facade method should be ran in a separate thread or not).

However, I have a feeling that there could be a better solution to my problem, whether it be a better way of forcing the method to me synchronous, eg with spring, or by testing the multithreading on some way.

This is where I need your suggestions, how would you solve my problem? Note, I'm using junit for both unit and integration tests.


Simple solution would be to return a Future object like this,

@Async
public Future<String> refreshFoorbar(CallBack cb) {
    yourHeavyLifting(); //asynchronous call
    return new AsyncResult<String>("yourJobNameMaybe");   
}

And in your test, take the future reference and call the get() method.

future.get(); // if its not already complete, waits for it to complete
assertTrue(yourTestCondition)

This blog post shows a sample.


When JUnit testing stuff like this, I use a testing callback with a CountDownLatch that gets counted down by the callback and await()ed by the test method.

private static class TestingCallback implements Callback {
    private final CountDownLatch latch;
    public TestingCallback(CountDownLatch latch) {
        this.latch = latch;
    }
    @Override public void onEvent() {
        this.latch.countDown();
    }
}

@Test
public void testCallback() {
    final CountDownLatch latch = new CountDownLatch(1);

    classUnderTest.execute( new TestCallback(latch) );

    assertTrue(latch.await(30, TimeUnit.SECONDS));
}

If the callback is invoked (asynchronously) by the code under test, the latch returns true and the test passes. If the callback doesn't get invoked, the test times out after thirty seconds and the assertion fails.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜