Skip to content

MockUnit

Andrei Ciobanu edited this page Mar 11, 2017 · 21 revisions

Generic Mock Units

is the generic interface that contains useful methods to manipulate data. It allows us to generate not only individual values but also collections (list, sets), maps, streams and arrays.

To better understand the power the MockUnits let's follow a simple example in which we want to generate Boolean values with a 35.25% probability of obtaining true.

For this we will create first a MockUnit<Boolean> object by calling the bools() method on MockNeat:

// Re-using a pre-existent ThreadLocal MockNeat Object
MockNeat mock = MockNeat.threadLocal();
// Creating our first MockUnit<Boolean>
MockUnit<Boolean> boolUnit = mock.bools();

We will want to go further and put a constraint on our MockUnit<Boolean> object.

We will add a new condition on our object by calling the probability(double) method.

This methods "recursively" returns a new instance of MockUnit<Boolean> but internally the boolean generating method will behave accordingly to our constraint.

MockUnit<Boolean> boolUnit = mock.bools().probability(35.50);

At this point we have created the "generation unit" of Booleans and all we need to do is make use of it, by calling the default MockUnit<T> methods:

val()

This method returns a single <T> value.

MockUnit<Boolean> boolUnit = mock.bools().probability(35.50);
Boolean val = boolUnit.val();

We can write all of the above simpler without keeping the reference:

Boolean val = mock.bools().probability(35.50).val();

Think of the val() method as the final step we doing before obtaining our values. This represents the "EXIT POINT" of a MockUnit chain.

valStr()

This method works exactly like val() but instead of returning directly it's value, it first calls toString on the object. If the generated object is null, it should return an empty String.

list()

Let's say we want to re-use the same MockUnit but this time we generate a List<Boolean> values, while keeping the same constraints. The List implementation is LinkedList, and it's size is 100:

MockUnit<Boolean> boolUnit = mock.bools().probability(35.50);
List<Boolean> list = boolUnit.list(LinkedList.class, 100).val();

The list method will return a new RandUnit but this time the returning type will be RandUnit<List<Boolean>>. It might look a little bit confusing but we can re-write the above code like this:

MockUnit<Boolean> boolUnit = mock.bools().probability(35.50);
MockUnit<List<Boolean>> listBoolUnit = boolUnit.list(LinkedList.class, 100);
List<Boolean> list = listBoolUnit.val();

If we stretch our minds even further we can generate a List<List<Boolean>> by creating the associated MockUnit<List<List<Boolean>>>.

MockUnit<Boolean> boolUnit = mock.bools().probability(35.50);
MockUnit<List<Boolean>> listBoolUnit = boolUnit.list(LinkedList.class, 100);
MockUnit<List<List<Boolean>>> listListBoolUnit = listBoolUnit.list(LinkedList.class, 100);
List<List<Boolean>> list = listListBoolUnit.val();

And we can go like this forever... well not exactly because after a few thousand List<List<List....<Boolean>..> we will eventually receive a StackOverFlow exception.

For making the code look more clean, there's no reason why we should keep references of MockUnits all the time.
We can simply start chaining our methods.

List<Boolean> list = mock.bools().probability(35.50).list(100).val();
List<List<Boolean>> listList = mock.bools().probability(35.50).list(100).list(100).val();
List<List<List<Boolean>>> listListList = mock.bools().probability(35.50).list(100).list(100).list(100).val();
// Show can go on (if there's a good reason...)

Note: If we don't specify the implementing List type, by default we will return an ArrayList.class

set()

This method works like the list one, with one exception: given the nature of Set we cannot guarantee a fixed size. We will generate N elements and add them into the Set, but if the elements are not unique, the Set will only keep what's possible. Duplicates won't be permitted.

Let's do a small exercise for fun.

We will generate 3 Booleans with a probability of returning true being 5%, and afterwards we put all the values a HashSet.

Let's see how many iterations we are going to have before we obtaining a Set with both true and false in it.

Set<Boolean> set;
for(int i = 0 ;; i++) {
    set = mock.bools().probability(5.0).set(3).val();
    if (set.size()==2) {
        System.out.println("Number of iterations: " + i);
        break;
    }
}

After running the snippet the value obtained was 9.

collection()

Collection<Boolean> vector = mock.bools()
                                 .probability(35.50)
                                 .collection(Vector.class, 100)
                                 .val();

mapKeys()

This allows us to build Map<T,R>s, mapping our MockUnit generated values with a Set of keys.

The method allow us to:

  • specify the number of elements in the map;
  • specify the map implementation;

The keys can be obtained from:

  • Another MockUnit;
  • From a Supplier<K>;
  • From an Iterable<K>;
  • From an generic array K[];
  • From primitives arrays: int[], double[], long[];

Examples:

Example 1. Obtaining a Map<Integer, Boolean> from an array of int[]:

int[] keys = { 100, 200, 300, 400, 500, 600 };
Map<Integer, Boolean> map = mock.bools().mapKeys(keys).val();

Possible output:

{400=true, 100=false, 500=false, 200=true, 600=true, 300=true}

Example 2. Obtaining a Map<Double, Boolean> from an Iterable<Double>:

This time we want the map implementation to be a LinkedHashMap.

Iterable<Double> iterable = unmodifiableList(asList(0.1, 0.2, 0.3, 0.4, 0.5));
Map<Double, Boolean> map = mock.bools().mapKeys(LinkedHashMap.class, iterable).val();

Possible output:

{0.1=true, 0.2=true, 0.3=false, 0.4=false, 0.5=true}

mapVals()

This allows us to build Map<T,R>s, mapping our MockUnit generated as keys for a given set of values.

The method allow us to:

  • specify the number of elements in the map;
  • specify the map implementation;

The values can be obtained from:

  • Another MockUnit;
  • From a Supplier<K>;
  • From an Iterable<K>;
  • From an generic array K[];
  • From primitives arrays: int[], double[], long[];

Example 1 Obtaining a Map<Boolean, Integer> from an array of int[]:

int[] values = { 100, 200, 300, 400, 500, 600 };
Map<Boolean, Integer> map = mock.bools().mapKeys(keys).val();

Possible output:

{false=500, true=600}

PS: It's normal to have only two keys false/true.

Example 2 Obtaining a Map<Boolean, Long> from another Supplier<Long>

Supplier<Long> longSupplier = () -> System.currentTimeMillis();
Map<Boolean, Long> map = mock.bools().mapVals(10, longSupplier).val();

Possible output:

{false=1487951761873, true=1487951761873}

stream()

Instead of obtaining a Collection, List, Set or a Map we can use the MockUnit<Boolean> to generate a Stream<Boolean>:

Stream<Boolean> stream = mock.bools().stream().val();

The Stream is infinite.

map()

This method allows us to do pre-processing on the values before they are actually generated.

The input parameter is a Function<T, R>. As you can see in the definition it is possible to change the return type of the next MockUnit in the chain.

For example, if we want to transform our MockUnit<Boolean> into a MockUnit<String> that holds the String values "true" and "false", we can do like this:

List<String> list = mock.bools().map((b) -> b.toString()).list(10).val();

mapToString a shortcut function that can to be used to "translate" the MockUnit<Boolean> into a MockUnitString, instead of MockUnit<String>.

List<String> list = mock.bools().mapToString().list(10).val();

If we want to translate the MockUnit<Boolean> into a MockUnitInt that returns 0s and 1s, we can use the shortcut method: mapToInt.

MockUnitInt mockInt = mock.bools().mapToInt(b -> (b) ? 1 : 0);
List<Integer> listInt = mockInt.list(10).val();

Or the shorter version of it (without keeping the intermediary reference):

List<Integer> listInt = mock.bools()
                            .mapToInt(b -> b ? 1 : 0)
                            .list(10)
                            .val();

A possible output:

[1, 0, 0, 1, 0, 0, 0, 0, 0, 0]

Similar shortcut methods exists for translating the MockUnit into a MockUnitDouble or a MockUnitLong.

Clone this wiki locally