简体   繁体   中英

Java Arguments.of() in a test case: How does it work?

I've been given test cases that are parameterized and use Stream.of and Arguments.of which I am not familiar with. As evidenced below the test case references the constructor of my class BofAAdapter and passes a BofA object. I'm wondering how to access in my class the integer (500) and the map of entries, or where they are being passed. I can't edit the test cases so I can't simply have them test with a different constructor. I'm just pretty lost here with what this test is doing.

@ParameterizedTest
    @MethodSource("providerBankAccountsGetDelinquent")
    public void testBankAccountsGetDelinquent(IBankAccounts adapter, int threshold, Map<Integer, Integer> expected) {
        Map<Integer, Integer> actual = adapter.getDelinquent( threshold );
        assertEqualMaps( expected, actual );
    }
    static Stream<Arguments> providerBankAccountsGetDelinquent() {
        return Stream.of(
                Arguments.of( new BofAAdapter( new BofA() ), 500, 
                        Map.ofEntries(
                            Map.entry( 1, 500),
                            Map.entry( 5,  20)
                        )),

Arguments is a concept from junit 5 .

You can read about what Arguments is about and how to use it, and what's happening here over at the junit site linked above.

To give you a quick overview: normally, a test method has no arguments. The test framework (junit5) will see a @Test annotation and will just run it.

But this is a different beast: This test method has.. parameters: Walk in the shoes of the test framework for a moment? How would you invoke this? What do you pass for 'adapter' and 'treshold'?

That's what the @MethodSource annotation is about: It's telling junit: FIRST, run the providerBankAccountsGetDelinquent method, which junit can do, because there are no arguments to pass. Then take the arguments that this method gave you, which is a stream (so, any number of instances of the Arguments class), and run this test method once for each Arguments object you got.

So, this ends up happening:

  1. junit calls providerBankAccountsGetDelinquent
  2. junit gets a Stream<Arguments> object.
  3. junit will start iterating through the stream.
  4. The stream will return the first (and only) object it will ever return: An Arguments object with threshold = 500, a new BofAAdapter, etc.
  5. It will then invoke testBankAccountsGetDelinquent with those arguments and print 'succeed' or 'fail' depending on the result of that test (which will depend on whether those maps are equal)
  6. junit asks the stream for the next object.
  7. The stream says: Nope, I'm all out, that one Arguments object is all I had.
  8. This part of the testing sequence is now complete.

In other words, all that code is a convoluted and silly way to just write:

@Test
public void testBankAccountsGetDelinquent() {
    IBankAccounts adapter = new BofAAdapter( new BofA() );
    int threshold = 500;
    Map<Integer, Integer> expected = Map.ofEntries(
                            Map.entry( 1, 500),
                            Map.entry( 5,  20)
                        );
    Map<Integer, Integer> actual = adapter.getDelinquent( threshold );
    assertEqualMaps(expected, actual);
}

Of course, presumably this code is either an example to show you how @ParameterizedTest works, or someone has a plan to expand on providerBankAccountsGetDelinquent .

Note that the general idea is that you use this @ParameterizedTest mechanism to create dynamic inputs. Imagine, for example, you want to run this test for all thresholds from 400 to 500, with the map changing too. Then this is one way to do that.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM