Skip to content

Commit

Permalink
MockFunction for more concise Function mocking. #25
Browse files Browse the repository at this point in the history
  • Loading branch information
Gabor Keszthelyi committed Oct 11, 2017
1 parent 029100f commit 49bf94d
Show file tree
Hide file tree
Showing 3 changed files with 277 additions and 0 deletions.
2 changes: 2 additions & 0 deletions test-utils/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ configurations {
apply from: '../publish.gradle'

dependencies {
compile project(':iterators')

compile 'junit:junit:' + JUNIT
compile 'org.hamcrest:hamcrest-all:' + HAMCREST
compile 'org.mockito:mockito-core:' + MOCKITO
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* Copyright 2017 dmfs GmbH
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.dmfs.testutils.mocks;

import org.dmfs.iterators.Function;
import org.dmfs.iterators.SingletonIterator;
import org.dmfs.jems.single.Single;
import org.mockito.Mockito;

import java.util.Iterator;

import static org.dmfs.testutils.TestDoubles.failingMock;


/**
* {@link Single} for a mock {@link Function} that expects on the provided arguments (fails on anything else) and returns the provided, corresponding results.
*
* @author Gabor Keszthelyi
*/
public final class MockFunction<Argument, Result> implements Single<Function<Argument, Result>>
{
private final Iterator<Argument> mExpectedArguments;
private final Iterator<Result> mMockResults;


public MockFunction(Iterator<Argument> expectedArguments, Iterator<Result> mockResults)
{
mExpectedArguments = expectedArguments;
mMockResults = mockResults;
}


public MockFunction(Iterable<Argument> expectedArguments, Iterable<Result> mockResults)
{
this(expectedArguments.iterator(), mockResults.iterator());
}


public MockFunction(Iterator<Argument> expectedArguments, Iterable<Result> mockResults)
{
this(expectedArguments, mockResults.iterator());
}


public MockFunction(Iterable<Argument> expectedArguments, Iterator<Result> mockResults)
{
this(expectedArguments.iterator(), mockResults);
}


public MockFunction(Argument argument, Result result)
{
this(new SingletonIterator<>(argument), new SingletonIterator<>(result));
}


@Override
public Function<Argument, Result> value()
{
Function<Argument, Result> mockFunction = failingMock(Function.class);

while (mExpectedArguments.hasNext())
{

if (!mMockResults.hasNext())
{
throw new IllegalArgumentException("Less results than arguments provided");
}

Mockito.doReturn(mMockResults.next()).when(mockFunction).apply(mExpectedArguments.next());
}

if (mMockResults.hasNext())
{
throw new IllegalArgumentException("Less arguments than results provided");
}

return mockFunction;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
/*
* Copyright 2017 dmfs GmbH
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.dmfs.testutils.mocks;

import org.dmfs.iterables.ArrayIterable;
import org.dmfs.iterators.ArrayIterator;
import org.dmfs.iterators.Function;
import org.junit.Test;

import static org.hamcrest.CoreMatchers.sameInstance;
import static org.hamcrest.MatcherAssert.assertThat;


/**
* Unit test for {@link MockFunction}.
*
* @author Gabor Keszthelyi
*/
public final class MockFunctionTest
{

private static final Object RES = new Object();
private static final Object RES_1 = new Object();
private static final Object RES_2 = new Object();
private static final Object RES_3 = new Object();


private static ValueObject arg(int value)
{
return new ValueObject(value);
}

@Test
public void test_singles_sameArg_pass()
{
assertThat(new MockFunction<>(arg(1), RES).value().apply(arg(1)), sameInstance(RES));
}


@Test(expected = AssertionError.class)
public void test_singles_differentArg_fail()
{
new MockFunction<>(arg(1), RES_1).value().apply(arg(2));
}


@Test
public void test_iterators_single_sameArg_pass()
{
assertThat(new MockFunction<>(new ArrayIterator<>(arg(1)), new ArrayIterator<>(RES)).value().apply(arg(1)), sameInstance(RES));
}


@Test(expected = AssertionError.class)
public void test_iterators_single_differentArg_fail()
{
new MockFunction<>(new ArrayIterator<>(arg(1)), new ArrayIterator<>(RES)).value().apply(arg(555));
}


@Test
public void test_iterators_multi_sameArg_pass()
{
Function<ValueObject, Object> mockFunction = new MockFunction<>(
new ArrayIterator<>(arg(1), arg(2), arg(3)),
new ArrayIterator<>(RES_1, RES_2, RES_3)).value();
assertThat(mockFunction.apply(arg(1)), sameInstance(RES_1));
assertThat(mockFunction.apply(arg(2)), sameInstance(RES_2));
assertThat(mockFunction.apply(arg(3)), sameInstance(RES_3));
}


@Test(expected = AssertionError.class)
public void test_iterators_multi_differentArg_fail()
{
Function<ValueObject, Object> mockFunction = new MockFunction<>(
new ArrayIterator<>(arg(1), arg(2), arg(3)),
new ArrayIterator<>(RES_1, RES_2, RES_3)).value();

assertThat(mockFunction.apply(arg(1)), sameInstance(RES_1));
mockFunction.apply(arg(555));
}


@Test(expected = IllegalArgumentException.class)
public void test_lessArgumentThanResult_throwsException()
{
new MockFunction<>(new ArrayIterator<>(arg(1)), new ArrayIterator<>(RES_1, RES_2)).value();
}


@Test(expected = IllegalArgumentException.class)
public void test_lessResultThanArgument_throwsException()
{
new MockFunction<>(new ArrayIterator<>(arg(1), arg(2)), new ArrayIterator<>(RES_1)).value();
}


@Test
public void test_iterable_iterable_pass()
{
assertThat(new MockFunction<>(new ArrayIterable<>(arg(1)), new ArrayIterable<>(RES)).value().apply(arg(1)), sameInstance(RES));
}


@Test
public void test_iterator_iterable_pass()
{
assertThat(new MockFunction<>(new ArrayIterator<>(arg(1)), new ArrayIterable<>(RES)).value().apply(arg(1)), sameInstance(RES));
}


@Test
public void test_iterable_iterator_pass()
{
assertThat(new MockFunction<>(new ArrayIterable<>(arg(1)), new ArrayIterator<>(RES)).value().apply(arg(1)), sameInstance(RES));
}


// TODO Use the top level class when/if available
public static final class ValueObject
{
private final int mValue;


public ValueObject(int value)
{
mValue = value;
}


@Override
public boolean equals(Object o)
{
if (this == o)
{
return true;
}
if (o == null || getClass() != o.getClass())
{
return false;
}

ValueObject that = (ValueObject) o;

return mValue == that.mValue;
}


@Override
public int hashCode()
{
return mValue;
}


@Override
public String toString()
{
return "ValueObject{" + mValue + '}';
}

}

}

0 comments on commit 49bf94d

Please sign in to comment.