JavaMoney/jsr354-ri

How to unit test monetary conversion?

mickaeltr opened this issue · 6 comments

Hello,

I was wondering what you would suggest for unit testing monetary conversion?

What I would expect from a unit test is:

  • to be repeatable (fixed currency rate?)
  • to work with no internet connection

That would be a great addition to the documentation.

Thanks

To be more precise, I have a function that sums EUR and GBP (converted to EUR) amounts and I want to assert that the final sum is as expected (hence that the conversion was made accordingly).

keilw commented

I don't think that's really something for the RI. And I don't recall a "Guidebook" or @otaviojava do you know one? To contribute here one must be a JCP member, but I don't see @mickaeltr that you are a JCP Member yet, are you?

Oh no, I am not @keilw, sorry if my request was inappropriate

keilw commented

It's free, but of course for this purpose alone you don't have to join @mickaeltr unless you have intentions beyond that? I struggle to find the right place. I remember @otaviojava once had a javamoney-book but it did not seem very active lately. It seems a kind of tutorial or examples, under certain circumstances it could also be good for javamoney-examples, both do not require JCP membership.

A quick update on this topic.

The best I managed to do was to disable most of the exchange rate providers, with the following javamoney.properties in my test resources:

load.ECBCurrentRateProvider.startRemote=false
load.ECBCurrentRateProvider.type=NEVER
load.ECBHistoric90RateProvider.startRemote=false
load.ECBHistoric90RateProvider.type=NEVER
load.ECBHistoricRateProvider.startRemote=false
load.ECBHistoricRateProvider.type=NEVER
load.IMFHistoricRateProvider.startRemote=false
load.IMFHistoricRateProvider.type=NEVER
load.IMFRateProvider.startRemote=false
load.IMFRateProvider.type=NEVER

For some reason it still does some remote calls and I could not setup a fixed exchange rate. So I isolated the code responsible for converting currency:

    public MonetaryAmount convertTo(MonetaryAmount money, CurrencyUnit unit) {
        // That makes remote calls to fetch exchange rates
        var conversion = MonetaryConversions.getConversion(unit);
        return money.with(conversion);
    }

… and added a fuzzy unit test:

        // Beware that this test is not strictly isolated because it makes remote calls to fetch exchange rates
        @Test
        void should_convert_gbp_to_eur() {
            // Given
            var gbp = Money.of(1, Monetary.getCurrency("GBP"));
            // When
            var eur = currencyRepository.convertTo(gbp, Monetary.getCurrency("EUR"));
            // Then
            Assertions.assertThat(eur.getNumber().doubleValue())
                // Using a range because exchange rate is not fixed
                .isGreaterThan(1)
                .isLessThan(2);
        }

That is not perfect but acceptable to me right now. So I am closing this issue. Thanks

keilw commented

@mickaeltr Thanks a lot for the update. Glad you found a working solution.
Especially about disabling some would you be interested and able to write about it somewhere?

Either in our Blog-like update section: http://javamoney.github.io/archive.html (I know the name "archive" may sound misleading, but no time to change a running system right now) or somewhere else, e.g. we could activate the "Wiki" here, too if it works better?