JUnit Test against an interface without having the implementation yet - testing

I try to write a test for a given interface like that with JUnit and have no idea how to do that:
public interface ShortMessageService {
/**
* Creates a message. A message is related to a topic
* Creates a date for the message
* #throws IllegalArgumentException, if the message is longer then 255 characters.
* #throws IllegalArgumentException, if the message ist shorter then 10 characters.
* #throws IllegalArgumentException, if the user doesn't exist
* #throws IllegalArgumentException, if the topic doesn't exist
* #throws NullPointerException, if one argument is null.
* #param userName
* #param message
* #return ID of the new created message
*/
Long createMessage(String userName, String message, String topic);
[...]
}
I tried to mock the interface after I realized that it doesn't make sense at all so I am a bit lost. Maybe someone can give me a good approach I can work with. I also heard about junit parameterized tests but I am not sure if that is what I am looking for.
Many thanks!

I use the following pattern to write abstract tests against my interface APIs without having any implementations available. You can write whatever tests you require in AbstractShortMessageServiceTest without having to implement them at that point in time.
public abstract class AbstractShortMessageServiceTest
{
/**
* #return A new empty instance of an implementation of FooManager.
*/
protected abstract ShortMessageService getNewShortMessageService();
private ShortMessageService testService;
#Before
public void setUp() throws Exception
{
testService = getNewShortMessageService();
}
#Test
public void testFooBar() throws Exception
{
assertEquals("question", testService.createMessage(
"DeepThought", "42", "everything"));
}
}
When you have an implementation, you can use the test simply by defining a new test class that overrides AbstractShortMessageServiceTest and implements the getNewShortMessageService method.
public class MyShortMessageServiceTest extends AbstractShortMessageServiceTest
{
protected ShortMessageService getNewShortMessageService()
{
return new MyShortMessageService();
}
}
In addition, if you need the test to be parameterized, you can do that in AbstractShortMessageServiceTest without doing it in each of the concrete tests.

Usually test is prepared for class that implements the interface and mocks are used for cooperating classes but you can test your test by mock if the class is not ready yet. It is unusual and you should use thenAnsfer with implemented logic of possible cases:
Better way is simply prepare tests for the implementation class and start to improve it till all test passes:
Implementing class can be in field and initialized before tests
private ShortMessageService testedClasOrMock;
//version with implementing class
#Before
public void setUp(){
testedClasOrMock = new ShortMessageServiceImpl0();
}
#Before
public void setUp(){
testedClasOrMock = mock(ShortMessageService.class);
when(testedClasOrMock).thenAnswer(new Answer<Long>(){
#Override
public Long answer(InvocationOnMock invocation) throws Throwable {
String message =(String) invocation.getArguments()[1];
if (message.length() > 256){
throw new IllegalArgumentException("msg is too long");
}
//other exception throwing cases
…...
return new Long(44);
}});
}
so you will have several test with expected exceptions like
#Test (expected= IllegalArgumentException.class)
public void testTooLongMsg(){
testedClasOrMock.createMessage(USER, TOO_LONG_MSG, TOPIC);
}
and one that simply should not throw exception and for instance check that msg ids are different
#Test
public void testTooLongMsg(){
long id0 = testedClasOrMock.createMessage(USER, TOO_LONG_MSG, TOPIC);
long id1 = testedClasOrMock.createMessage(USER, TOO_LONG_MSG, TOPIC);
assertTrue(id0 != id1);
}
If you insist on testing your test by mock let me know and I will add example for one test case.

Related

#SuppressStaticInitializationFor partial mocking

I have this weird case where I want to test "some" functionality without touching the other... it's very hard for me to choose a proper description and I hope that the code I will present below is pretty much self descriptive.
Suppose I have a class that keeps some strategies:
class TypeStrategy {
private static final CreateConsumer CREATE_CONSUMER = new CreateConsumer();
private static final ModifyConsumer MODIFY_CONSUMER = new ModifyConsumer();
private static final Map<Type, Consumer<ConsumerContext>> MAP = Map.of(
Type.CREATE, CREATE_CONSUMER,
Type.MODIFY, MODIFY_CONSUMER
);
public static void consume(Type type, ConsumerContext context) {
Optional.ofNullable(MAP.get(nodeActionType))
.orElseThrow(strategyMissing(type))
.accept(context);
}
}
The idea is very easy - there are some strategies that are registered for a certain Type; method consume will simply try to find a proper registered type and invoke consume on it with the supplied ConsumerContext.
And now the problem: I very much want to test that all the strategies I care about are registered and I can invoke accept on them - that is literally all I want to test.
Usually, I would use #SuppressStaticInitializationFor on the TypeStrategy and using WhiteBox::setInternalState would just put whatever I need for CREATE_CONSUMER and MODIFY_CONSUMER; but in this case I can't, because the MAP will be skipped also and I really don't want that, all I care about is those two strategies - I need the MAP to stay as it is.
Besides some nasty refactoring, that does get me where I sort of want to be, I am out of ideas how can I achieve this. In the best case scenario I hoped that #SuppressStaticInitializationFor would support some "partial" skipping, where you could specify some filter on what exactly you want skipped , but that is not an option, really.
I could also test "everything" else on the chain of calls - that is test everything that accept is supposed to do, but that adds close to 70 lines of mocking in this test and it becomes a nightmare to understand that it really wants to test a very small piece.
From your description it seems black-box testing is not an option, so perhaps we can rely on some white-box tests by mocking the constructors of your consumers, and verifying their interactions.
Below you can find a complete example extrapolated from your initial sample, including a possible option for .orElseThrow(strategyMissing(type)).
One important note/disclaimer: since we're leaving TypeStrategy intact, this means the static initialization block for the map will be executed. Thus, we need to pay special attention to the consumer mock instances. We need to make sure that the same mock instances added in the map during the initial mocking phase, are available in all the tests, otherwise the verification will fail. So instead of creating mocks for each test, we will create them once for all tests. While this is not recommended in unit testing (tests should be isolated and independent), I believe in this special case it's a decent trade-off one can live with.
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import java.util.AbstractMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.*;
import static org.powermock.api.mockito.PowerMockito.whenNew;
// enable powermock magic
#RunWith(PowerMockRunner.class)
#PrepareForTest({MockitoTest.TypeStrategy.class})
public class MockitoTest {
private static CreateConsumer createConsumerMock;
private static ModifyConsumer modifyConsumerMock;
// static initializer in TypeStrategy => mock everything once in the beginning to avoid having new mocks for each test (otherwise "verify" will fail)
#BeforeClass
public static void setup() throws Exception {
// mock the constructors to return mocks which we can later check for interactions
createConsumerMock = mock(CreateConsumer.class);
modifyConsumerMock = mock(ModifyConsumer.class);
whenNew(CreateConsumer.class).withAnyArguments().thenReturn(createConsumerMock);
whenNew(ModifyConsumer.class).withAnyArguments().thenReturn(modifyConsumerMock);
}
#Test
public void shouldDelegateToCreateConsumer() {
checkSpecificInteraction(Type.CREATE, createConsumerMock);
}
#Test
public void shouldDelegateToModifyConsumer() {
checkSpecificInteraction(Type.MODIFY, modifyConsumerMock);
}
private void checkSpecificInteraction(Type type, Consumer<ConsumerContext> consumer) {
ConsumerContext expectedContext = new ConsumerContext();
// invoke the object under test
TypeStrategy.consume(type, expectedContext);
// check interactions
verify(consumer).accept(expectedContext);
}
#Test
public void shouldThrowExceptionForUnsupportedConsumer() {
ConsumerContext expectedContext = new ConsumerContext();
// unsupported type mock
Type unsupportedType = PowerMockito.mock(Type.class);
when(unsupportedType.toString()).thenReturn("Unexpected");
// powermock does not play well with "#Rule ExpectedException", use plain old try-catch
try {
// invoke the object under test
TypeStrategy.consume(unsupportedType, expectedContext);
// if no exception was thrown to this point, the test is failed
fail("Should have thrown exception for unsupported consumers");
} catch (Exception e) {
assertThat(e.getMessage(), is("Type [" + unsupportedType + "] not supported"));
}
}
/* production classes below */
public static class TypeStrategy {
private static final CreateConsumer CREATE_CONSUMER = new CreateConsumer();
private static final ModifyConsumer MODIFY_CONSUMER = new ModifyConsumer();
private static final Map<Type, Consumer<ConsumerContext>> MAP = Stream.of(
new AbstractMap.SimpleEntry<>(Type.CREATE, CREATE_CONSUMER),
new AbstractMap.SimpleEntry<>(Type.MODIFY, MODIFY_CONSUMER)
).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
public static void consume(Type type, ConsumerContext context) {
Optional.ofNullable(MAP.get(type))
.orElseThrow(strategyMissing(type))
.accept(context);
}
private static Supplier<IllegalArgumentException> strategyMissing(Type type) {
return () -> new IllegalArgumentException("Type [" + type + "] not supported");
}
}
public static class CreateConsumer implements Consumer<ConsumerContext> {
#Override
public void accept(ConsumerContext consumerContext) {
throw new UnsupportedOperationException("Not implemented");
}
}
public static class ModifyConsumer implements Consumer<ConsumerContext> {
#Override
public void accept(ConsumerContext consumerContext) {
throw new UnsupportedOperationException("Not implemented");
}
}
public enum Type {
MODIFY, CREATE
}
public static class ConsumerContext {
}
}

Apache Ignite Caching and PeerClassLoading

1. Is it possible to put non-POJO class instances as the value of a cache?
For example, I have a QueryThread class which is a subclass of java.lang.Thread and I am trying to put this instance in a cache. It looks like the put operation is failing because this cache is always empty.
Consider the following class:
public class QueryThread extends Thread {
private IgniteCache<?, ?> cache;
private String queryId;
private String query;
private long timeIntervalinMillis;
private volatile boolean running = false;
public QueryThread(IgniteCache<?, ?> dataCache, String queryId, String query, long timeIntervalinMillis) {
this.queryId = queryId;
this.cache = dataCache;
this.query = query;
this.timeIntervalinMillis = timeIntervalinMillis;
}
public void exec() throws Throwable {
SqlFieldsQuery qry = new SqlFieldsQuery(query, false);
while (running) {
List<List<?>> queryResult = cache.query(qry).getAll();
for (List<?> list : queryResult) {
System.out.println("result : "+list);
}
System.out.println("..... ");
Thread.sleep(timeIntervalinMillis);
}
}
}
This class is not a POJO. How do I store an instance of this class in the cache?
I tried implementing Serializable (didn't help).
I need to be able to do this:
queryCache.put(queryId, queryThread);
Next I tried broadcasting the class using the IgniteCallable interface. But my class takes multiple arguments in the constructor. I feel PeerClassLoading is easy if the class takes a no-arg constructor:
IgniteCompute compute = ignite.compute(ignite.cluster().forServers());
compute.broadcast(new IgniteCallable<MyServiceImpl>() {
#Override
public MyServiceImpl call() throws Exception {
MyServiceImpl myService = new MyServiceImpl();
return myService;
}
});
2. How do I do PeerClassLoading in the case of a class with multi-arg constructor?
It's restricted to put Thread instances to the cache, Thread instance cannot be serialized due to call to Native Methods. Thats why you always get empty value.
PeerClassLoading is a special distributed ClassLoader in Ignite for inter-node byte-code exchange. So, it's only about sharing classes between nodes. It doesn't make sense how many arguments in constructor class have.
But, on the other hand, object, that you created, will be serialised and sent to other nodes and for deserialisation it will need a default(non-arg) constructor.

NSubstitute: Received Calls asserts wrongly

I've created this test:
[TestFixture]
public class UsersTests
{
private Core.Kernel coreKernel;
private Core.Configuration.ICoreConfiguration coreConfiguration;
[SetUp]
public void SetUp()
{
this.coreConfiguration = NSubstitute.Substitute.For<Core.Configuration.ICoreConfiguration>();
this.coreKernel = NSubstitute.Substitute.For<Core.Kernel>(this.coreConfiguration);
this.coreKernel.Initialize();
}
[Test]
public void AddUserTest()
{
Core.Communication.Entities.UserIdentity receivedUserIdentity = new Core.Communication.Entities.UserIdentity("user1", "passwd1");
((Core.Communication.ICoreService)this.coreKernel).AddUserIdentity(receivedUserIdentity);
this.coreKernel.Received(100).AddUser(Arg.Is<Core.Identity.UserIdentity>(u => u.UserId.Equals(receivedUserIdentity.UserId)));
}
}
where Core.Kernel is:
public partial class Kernel : Core.IKernel
{
public Kernel(Configuration.ICoreConfiguration configuration)
: this(configuration, null, Enumerable.Empty<Type>())
{
}
public Kernel(Configuration.ICoreConfiguration configuration, Communication.ICoreService service, IEnumerable<Type> producerTypes)
{
if (configuration == null)
throw new ArgumentException("configuration object must be provided", "configuration");
if (producerTypes.Any(t => !t.IsAssignableFrom(typeof(Core.Extensibility.AbstractProducerPlugin))))
throw new ArgumentException("All types must inherit from AbstractProducerPlugin", "plugins");
this.state = KernelState.initializing;
this.configuration = configuration;
this.service = service ?? this;
this.producerTypes = producerTypes;
this.backends = new Dictionary<Core.Identity.DomainIdentity, Backend.Infrastructure.IBackend>();
}
internal virtual void AddUser(Core.Identity.UserIdentity userIdentity) {...}
}
Nevertheless, this.coreKernel.Received(100).AddUser(... is not called 100 times, only one. What am I doing wrong?
I mean, I'm not trying to make 100 calls to AddUser. I'm checking AddUser should be called 100 times. So, assertion should fail.
EDIT
Guess this code (Core.IKernel.AddUserIdentity(...) implementation):
public class Core.Kernel {
public override void Core.IKernel.AddUserIdentity(UserIdentity userIdentity) {
this.AddUser(userIdentity); <<----- AddUser(...) is called
}
}
I think the problem is related with:
Core.Kernel implements Core.IKernel. Core.IKernel has AddUserIdentity(...) method.
I'm mocking Core.Kernel instead of mocking a Core.IKernel.
According to Core.IKernel.AddUserIdentity(...) method implementation AddUser should ne reached.
AddUser is an internal virtual method of Core.Kernel. It's not an implementation of any method interface.
I want to assert AddUser is called once when AddUserIdentity is reached.
Other questions about mocking:
For<T> where T is a concrete class -> virtual methods are replaced? no virtual methods are executed?
ForPartsOf<T> where T is a concrete class -> Which parts of this class are mocked (virtual methods, overrided interface methods)?
It is only called once because you are only calling AddUser once. The Received assertion checks how many times it has been called, it doesn't tell NSubstitue to call your method 100 times, you need to do that manually :)
NSubstitute also gives you the option of asserting a specific number of calls were received by passing an integer to Received(). This will throw if the substitute does not receive exactly that many matching calls
http://nsubstitute.github.io/help/received-calls/

Spring Batch JdbcBatchItemWriter setSql never throws exception

My simple flow of batch process reads from a CSV file and write into a MySQL database (batch configuration is ok and works).
I'm using a custom implementation of JdbcBatchItemWriter in order to do the job and I'm actually making an Update in my writer constructor.
CsvReader.java
#Component
#StepScope
public class EducationCsvReader extends FlatFileItemReader {
public final static String CSV_FILE_NAME = "education.csv.file";
#Value("#{jobParameters['"+ CSV_FILE_NAME +"']}")
public void setResource(final String csvFileName) throws Exception {
setResource(
new FileSystemResource(csvFileName)
);
}
public EducationCsvReader() {
setLinesToSkip(1);
setEncoding("UTF-8");
setStrict(true);
setLineMapper((line, num) -> {
String[] values = line.split(";");
return new Education()
.setName(values[2].trim())
.setId(Integer.parseInt(values[0].trim()));
});
}
}
my custom JdbcBatchItemWriter : AbstractJdbcBatchItemWriter.java
public abstract class AbstractJdbcBatchItemWriter<T> extends JdbcBatchItemWriter<T>{
#Autowired
public AbstractJdbcBatchItemWriter(String SQL_QUERY) {
setSql(SQL_QUERY);
}
#Autowired
#Override
public void setItemSqlParameterSourceProvider(
#Qualifier("beanPropertyItemSqlParameterSourceProvider") ItemSqlParameterSourceProvider provider){
super.setItemSqlParameterSourceProvider(provider);
}
#Autowired
#Override
public void setDataSource(#Qualifier("mysqlDataSource") DataSource dataSource){
super.setDataSource(dataSource);
}
}
And here is my writer implementation : MySQLWriter.java
#Component
public class EducationMysqlWriter extends AbstractJdbcBatchItemWriter<Education> {
public EducationMysqlWriter(){
super("");
try {
setSql("UPDATE ecole SET nom=:name WHERE id=:id");
} catch (EmptyResultDataAccessException exception){
setSql("INSERT INTO ecole (nom, id) VALUES (:name, :id");
}
}
}
I need to update rows but if it fails (EmptyResultDataAccessException) I need to do an Insert.
But EmptyResultDataAccessException is shown on log console and kills the job but the exception catching is never reachable into MySQLWriter.java ...
JdbcBatchItemWriter#setSql doesn't throw an exception because it doesn't do anything but assign a string to an instance variable. The try block in the constructor doesn't have anything to do with the write method, it is executed when the itemwriter is first instantiated, while the write method is executed once for each chunk of items being processed. If you read the stacktrace I expect you'll see the JdbcBatchtemWriter is executing its write method and throwing the exception.
The ItemWriter is not going to get instantiated for each row so, assuming you will have some rows that need to be inserted and some that need to be updated, setting the sql string in the constructor does not seem like a good idea.
You could override the ItemWriter#write method, using a separate sql string for the insert, but it would be easier to use one string using the mysql upsert syntax:
INSERT INTO ecol (nom, id) VALUES (:name, :id)
ON DUPLICATE KEY UPDATE nom = :name;

EasyMock Testing Void With Runnable

I'm trying to test the following class (I've left out the implementation)
public class UTRI implements UTR {
public void runAsUser(String userId, Runnable r);
}
This is the way I would use it:
UTRI.runAsUser("User1", new Runnable () {
private void run() {
//do whatever needs to be done here.
}
});
The problem is, I don't know how to use EasyMock to test functions that return void. That and I'm also not too familiar with testing in general (right out of school!). Can someone help explain to me what I need to do to approach this? I was thinking about making the UTRI a mock and doing expectlastcall after that, but realistically, not sure.
public class UTRITest {
UTRI utri = new UTRI();
#Test
public void testRunAsUser() {
// Create Mocks
Runnable mockRunnable = EasyMock.createMock(Runnable.class);
// Set Expectations
**mockRunnable.run();
EasyMock.expectLastCall().once();**
EasyMock.replay(mockRunnable);
// Call the method under test
utri.runAsUser("RAMBO", **mockRunnable**);
// Verify if run was called on Runnable!!
EasyMock.verify(mockRunnable);
}
}