From 1ddd46f1afdcaf6364e3b1b5cf67cefd91747f4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ho=C3=A0ng=20H=C6=B0ng?= Date: Thu, 21 Sep 2017 21:04:55 +0700 Subject: [PATCH] BAEL-1080 Introduction to Future in Vavr (#2627) * Add example of different types of bean injection * BAEL-1080 Introduction to Future and Pattern Matching in Vavr * Update future with Pattern Matching * remove unused files * Update future unit test of cancelled Future * remove unused import * delete unused files * using await() on future to wait until future completed instead of using while(true) * Add Awaitability to FutureTest, avoid using while loop * format code * add some static void method that print the result to console --- .../baeldung/vavr/future/FutureUnitTest.java | 144 ++++++++++++++---- 1 file changed, 115 insertions(+), 29 deletions(-) diff --git a/vavr/src/test/java/com/baeldung/vavr/future/FutureUnitTest.java b/vavr/src/test/java/com/baeldung/vavr/future/FutureUnitTest.java index 84621e3a68..437742c964 100644 --- a/vavr/src/test/java/com/baeldung/vavr/future/FutureUnitTest.java +++ b/vavr/src/test/java/com/baeldung/vavr/future/FutureUnitTest.java @@ -5,17 +5,23 @@ import static io.vavr.API.Case; import static io.vavr.API.Match; import static io.vavr.Predicates.exists; import static io.vavr.Predicates.forAll; -import static org.awaitility.Awaitility.await; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.util.concurrent.CancellationException; +import java.util.function.Consumer; import java.util.function.Predicate; import org.junit.Test; +import org.mockito.Mockito; +import org.mockito.internal.verification.VerificationModeFactory; +import org.mockito.verification.Timeout; +import io.vavr.Tuple; +import io.vavr.Tuple2; import io.vavr.collection.List; import io.vavr.concurrent.Future; +import io.vavr.control.Try; public class FutureUnitTest { @@ -26,8 +32,7 @@ public class FutureUnitTest { public void givenFunctionReturnInteger_WhenCallWithFuture_ShouldReturnFunctionValue() { Future future = Future.of(() -> 1); - assertEquals(1, future.get() - .intValue()); + assertEquals(1, future.get().intValue()); } @Test @@ -57,33 +62,29 @@ public class FutureUnitTest { @Test public void givenFunction_WhenCallWithFutureAndRegisterConsumerForSuccess_ShouldCallConsumerToStoreValue() { - final int[] store = new int[] { 0 }; Future future = Future.of(() -> 1); - future.onSuccess(i -> { - store[0] = i; - }); - await().until(() -> store[0] == 1); + MockConsumer consumer = Mockito.mock(MockConsumer.class); + future.onSuccess(consumer); + Mockito.verify(consumer, new Timeout(1000, VerificationModeFactory.times(1))).accept(1); } @Test public void givenFunctionThrowException_WhenCallWithFutureAndRegisterConsumerForFailer_ShouldCallConsumerToStoreException() { - final Throwable[] store = new Throwable[] { null }; Future future = Future.of(() -> getResourceThrowException("")); - future.onFailure(err -> store[0] = err); - await().until(() -> RuntimeException.class.isInstance(store[0])); + MockThrowableConsumer consumer = Mockito.mock(MockThrowableConsumer.class); + future.onFailure(consumer); + Mockito.verify(consumer, new Timeout(1000, VerificationModeFactory.times(1))).accept(Mockito.any()); } @Test public void givenAFuture_WhenAddAndThenConsumer_ShouldCallConsumerWithResultOfFutureAction() { - int[] store1 = new int[1]; - int[] store2 = new int[1]; + MockTryConsumer consumer1 = Mockito.mock(MockTryConsumer.class); + MockTryConsumer consumer2 = Mockito.mock(MockTryConsumer.class); Future future = Future.of(() -> 1); - Future andThenFuture = future.andThen(i -> store1[0] = i.get() + 1) - .andThen(i -> store2[0] = store1[0] + 1); + Future andThenFuture = future.andThen(consumer1).andThen(consumer2); andThenFuture.await(); - - assertEquals(2, store1[0]); - assertEquals(3, store2[0]); + Mockito.verify(consumer1, VerificationModeFactory.times(1)).accept(Try.success(1)); + Mockito.verify(consumer2, VerificationModeFactory.times(1)).accept(Try.success(1)); } @Test @@ -91,8 +92,7 @@ public class FutureUnitTest { Future future = Future.failed(new RuntimeException()); Future future2 = future.orElse(Future.of(() -> 2)); - assertEquals(2, future2.get() - .intValue()); + assertEquals(2, future2.get().intValue()); } @Test(expected = CancellationException.class) @@ -124,17 +124,46 @@ public class FutureUnitTest { Future future = Future.failed(new RuntimeException()); Future fallbackFuture = Future.of(() -> expectedResult); Future futureResult = future.fallbackTo(fallbackFuture); - futureResult.await(); assertEquals(expectedResult, futureResult.get()); } + + @Test + public void givenAFuture_WhenTransformByAddingOne_ShouldReturn() { + Future future = Future.of(() -> 1).transformValue(f -> Try.of(() -> "Hello: " + f.get())); + + assertEquals("Hello: 1", future.get()); + } + + @Test + public void givenAFutureOfInt_WhenMapToString_ShouldCombineAndReturn() { + Future future = Future.of(()->1).map(i -> "Hello: " + i); + + assertEquals("Hello: 1", future.get()); + } + + @Test + public void givenAFutureOfInt_WhenFlatMapToString_ShouldCombineAndReturn() { + Future futureMap = Future.of(() -> 1).flatMap((i) -> Future.of(() -> "Hello: " + i)); + + assertEquals("Hello: 1", futureMap.get()); + } + + @Test + public void givenAFutureOf2String_WhenZip_ShouldReturnTupleOf2String() { + Future> future = Future.of(() -> "hello").zip(Future.of(() -> "world")); + + assertEquals(Tuple.of("hello", "world"), future.get()); + } @Test public void givenGetResourceWithFuture_WhenWaitAndMatchWithPredicate_ShouldReturnSuccess() { String url = "http://resource"; Future future = Future.of(() -> getResource(url)); future.await(); - String s = Match(future).of(Case($(future0 -> future0.isSuccess()), SUCCESS), Case($(), FAILURE)); + String s = Match(future).of( + Case($(future0 -> future0.isSuccess()), SUCCESS), + Case($(), FAILURE)); assertEquals(SUCCESS, s); } @@ -143,7 +172,9 @@ public class FutureUnitTest { public void givenAFailedFuture_WhenWaitAndMatchWithPredicateCheckSuccess_ShouldReturnFailed() { Future future = Future.failed(new RuntimeException()); future.await(); - String s = Match(future).of(Case($(future0 -> future0.isSuccess()), SUCCESS), Case($(), FAILURE)); + String s = Match(future).of( + Case($(future0 -> future0.isSuccess()), SUCCESS), + Case($(), FAILURE)); assertEquals(FAILURE, s); } @@ -155,7 +186,10 @@ public class FutureUnitTest { return 1; }); Predicate> predicate = f -> f.exists(i -> i % 2 == 1); - String s = Match(future).of(Case($(predicate), "Even"), Case($(), "Odd")); + + String s = Match(future).of( + Case($(predicate), "Even"), + Case($(), "Odd")); assertEquals("Even", s); } @@ -164,7 +198,9 @@ public class FutureUnitTest { public void givenAListOfFutureReturnFist3Integers_WhenMatchWithExistEvenNumberPredicate_ShouldReturnSuccess() { List> futures = getFutureOfFirst3Number(); Predicate> predicate0 = future -> future.exists(i -> i % 2 == 0); - String s = Match(futures).of(Case($(exists(predicate0)), "Even"), Case($(), "Odd")); + String s = Match(futures).of( + Case($(exists(predicate0)), "Even"), + Case($(), "Odd")); assertEquals("Even", s); } @@ -173,7 +209,9 @@ public class FutureUnitTest { public void givenAListOfFutureReturnFist3Integers_WhenMatchWithForAllNumberBiggerThanZeroPredicate_ShouldReturnSuccess() { List> futures = getFutureOfFirst3Number(); Predicate> predicate0 = future -> future.exists(i -> i > 0); - String s = Match(futures).of(Case($(forAll(predicate0)), "Positive numbers"), Case($(), "None")); + String s = Match(futures).of( + Case($(forAll(predicate0)), "Positive numbers"), + Case($(), "None")); assertEquals("Positive numbers", s); } @@ -182,13 +220,19 @@ public class FutureUnitTest { public void givenAListOfFutureReturnFist3Integers_WhenMatchWithForAllNumberSmallerThanZeroPredicate_ShouldReturnFailed() { List> futures = getFutureOfFirst3Number(); Predicate> predicate0 = future -> future.exists(i -> i < 0); - String s = Match(futures).of(Case($(forAll(predicate0)), "Negative numbers"), Case($(), "None")); + String s = Match(futures).of( + Case($(forAll(predicate0)), "Negative numbers"), + Case($(), "None")); assertEquals("None", s); } - private String getResource(String url) throws InterruptedException { - Thread.sleep(10); + private String getResource(String url) { + try { + Thread.sleep(10); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } return "Content from " + url; } @@ -200,4 +244,46 @@ public class FutureUnitTest { List> futures = List.of(Future.of(() -> 1), Future.of(() -> 2), Future.of(() -> 3)); return futures; } + + private static void checkOnSuccessFunction() { + Future future = Future.of(() -> 1); + future.onSuccess(i -> System.out.println("Future finish with result: " + i)); + } + + private static void checkOnFailureFunction() { + Future future = Future.of(() -> {throw new RuntimeException("Failed");}); + future.onFailure(t -> System.out.println("Future failures with exception: " + t)); + } + + private static void runAndThenConsumer() { + Future future = Future.of(() -> 1); + future.andThen(i -> System.out.println("Do side-effect action 1 with input: " + i.get())). + andThen((i) -> System.out.println("Do side-effect action 2 with input: " + i.get())); + } + + public static void main(String[] args) throws InterruptedException { + checkOnSuccessFunction(); + checkOnFailureFunction(); + runAndThenConsumer(); + Thread.sleep(1000); + } +} + + +class MockConsumer implements Consumer { + @Override + public void accept(Integer t) { + } +} + +class MockTryConsumer implements Consumer> { + @Override + public void accept(Try t) { + } +} + +class MockThrowableConsumer implements Consumer { + @Override + public void accept(Throwable t) { + } }