Theory test is relatively new feature in JUnit testing.
In theory test, we define "theory" for parameter combination and filter them by "assume". Then only tests passed parameters by assume.
Let's show you some example theory test code. In Junit test,
The code below shows how theory test works in JUnit. Actually this is not good example because there is no advantedges compared with parameterized test in this case.
I show you better example now.
In the below example test class will test all combination of currencies annotated by @DataPoints. e.g. USD-USD, USD-CAD, USD-JPY, etc...
And the parametesr (data) only passed assume condition will be tested at test method.
Using theory test, you don't have to write all currency combination for parameters!!
In theory test, we define "theory" for parameter combination and filter them by "assume". Then only tests passed parameters by assume.
Let's show you some example theory test code. In Junit test,
- we put @RunWith(Theories.class) annotation on test class for deining theory test.
- put @DataPoints for parameter data set.
The code below shows how theory test works in JUnit. Actually this is not good example because there is no advantedges compared with parameterized test in this case.
package com.dukesoftware.exchangerate.service; import junit.framework.Assert; import org.junit.After; import org.junit.BeforeClass; import org.junit.experimental.theories.DataPoints; import org.junit.experimental.theories.Theories; import org.junit.experimental.theories.Theory; import org.junit.runner.RunWith; import org.mockito.Mockito; import com.dukesoftware.exchangerate.api.ExchangeRateApi; import com.dukesoftware.exchangerate.api.Rate; import com.dukesoftware.exchangerate.service.PriceCalculator; @RunWith(Theories.class) public class PriceCalculatorTheoryTest { // write parameters here... @DataPoints public static Object[] parameters() { return new Object[][]{ { 100d, 1.0395, "JPY", "USD"}, { 100d, 2.4045, "PHP", "USD"}, { 10000d, 1.05, "IDR", "USD"} }; } private static PriceCalculator SERVICE; private static ExchangeRateApi MOCK_API; @BeforeClass public static void setUp() { // create mock MOCK_API = Mockito.mock(ExchangeRateApi.class); setUpRateOnMockApi("JPY", "USD", 0.0099); setUpRateOnMockApi("PHP", "USD", 0.0229); setUpRateOnMockApi("IDR", "USD", 1.0E-4); // inject SERVICE = new PriceCalculator(MOCK_API); SERVICE.initialize(); } @After public void tearDown() { SERVICE.shutdown(); } @Theory public void testCalculatePrice(Object[] input) { double price = (double)input[0]; double expectedPrice = (double)input[1]; String ccy1 = (String)input[2]; String ccy2 = (String)input[3]; double actualPrice = SERVICE.calculatePrice(price, ccy1, ccy2); Assert.assertEquals("failed on " + ccy1 + ":" + ccy2, expectedPrice, actualPrice, 0.00001); } private static void setUpRateOnMockApi(String ccy1, String ccy2, double value) { Rate rate = new Rate(); rate.setCcy1(ccy1); rate.setCcy1(ccy2); rate.setValue(value); Mockito.when(MOCK_API.getRate(ccy1, ccy2)).thenReturn(rate); } }
I show you better example now.
In the below example test class will test all combination of currencies annotated by @DataPoints. e.g. USD-USD, USD-CAD, USD-JPY, etc...
And the parametesr (data) only passed assume condition will be tested at test method.
Using theory test, you don't have to write all currency combination for parameters!!
package com.dukesoftware.exchangerate.api; import java.util.HashSet; import java.util.Set; import junit.framework.Assert; import org.junit.Assume; import org.junit.BeforeClass; import org.junit.experimental.theories.DataPoints; import org.junit.experimental.theories.Theories; import org.junit.experimental.theories.Theory; import org.junit.runner.RunWith; @RunWith(Theories.class) public class CachedCurrencyRateApiTest { private static CachedExchangeRateApi API; private static Set<String> CHECKED_CCY1 = new HashSet<>(); @BeforeClass public static void setUp() { API = new CachedExchangeRateApi(new YahooExchangeRateApi()); } @DataPoints public static String[] CURRENCIES_US = new String[]{ "USD", "CAD"}; @DataPoints public static String[] CURRENCIES_ASIA = new String[]{ "JPY", "PHP", "IDR"}; // @DataPoints public static String[] CURRENCIES_EU = new String[]{ "EUR", "CHF"}; @Theory public void theoryReversedRateValidate(String ccy1, String ccy2) { // !!KEY PART!! - using Assume Assume.assumeTrue(!ccy1.equals(ccy2)); Assume.assumeTrue(!CHECKED_CCY1.contains(ccy2)); CHECKED_CCY1.add(ccy1); System.out.println(ccy1 + "," + ccy2); Rate rate1 = API.getRate(ccy1, ccy2); Rate rate2 = API.getRate(ccy2, ccy1); waitFor(1000); Assert.assertEquals(rate1.getValue(), 1d / rate2.getValue(), 0.00001); Assert.assertEquals(rate1.getDate(), rate2.getDate()); } private static void waitFor(long millis) { try { Thread.sleep(millis); } catch (InterruptedException e) { e.printStackTrace(); } } }
package com.dukesoftware.exchangerate.api; import java.util.HashMap; import java.util.Map; public class CachedExchangeRateApi implements ExchangeRateApi { private final ExchangeRateApi api; private final Map<String,Rate> map = new HashMap<>(); public CachedExchangeRateApi(ExchangeRateApi api) { this.api = api; } @Override public Rate getRate(String ccy1, String ccy2) { String key = generateKey(ccy1, ccy2); Rate rate = map.get(key); if(rate == null) { rate = api.getRate(ccy1, ccy2); map.put(key, rate); // put reverse ccy combination as well Rate rateReversed = new Rate(); rateReversed.setCcy1(ccy2); rateReversed.setCcy2(ccy1); rateReversed.setValue(1d / rate.getValue()); rateReversed.setDate(rate.getDate()); map.put(generateKey(ccy2, ccy1), rateReversed); } return rate; } private String generateKey(String ccy1, String ccy2) { return ccy1+":"+ccy2; } }
コメント