Hot questions for Using Cassandra in unit testing

Top Java Programmings / Cassandra / unit testing

Question:

I have following code preparing mocks to test my service using Cassandra (I need to mock com.datastax.driver.core.ColumnDefinitions.Definition) :

@RunWith(PowerMockRunner.class)
public class TestMyClass{
private MyClass target;
  @Before
  public void setUp() throws Exception {
    ColumnDefinitions mockColumnDefinitions=Mockito.mock(ColumnDefinitions.class);
    Mockito.when(mockRow.getColumnDefinitions()).thenReturn(mockColumnDefinitions);
    target= new MyClass();
    Definition mockDef = Mockito.mock(Definition.class);
    List<Definition> defList = new ArrayList<Definition>();
    defList.add(mockDef);
    Iterator mockIterator = Mockito.mock(Iterator.class);
    Mockito.when(mockColumnDefinitions.iterator()).thenReturn(mockIterator);
    Mockito.when(mockIterator.hasNext()).thenReturn(true, false);
    Mockito.when(mockIterator.next()).thenReturn(mockDef);
    Mockito.when(mockDef.getName()).thenReturn(NAME);
  }
 @Test
 public void testMyMethod() throws Exception {
    target.MyMethod();
 }
}

Test execution goes fine this place, and I have this type of code in different places, so it should work. Inside the service I am testing I have following code:

ColumnDefinitions colDef = row.getColumnDefinitions();
Iterator<Definition> defIterator = colDef.iterator();
while (defIterator.hasNext()) {
    Definition def = defIterator.next();
    String columnName = def.getName();
}

When I debug this code, I see, that both colDef and defIterator are mocked successfully. I see something like that in debug variables area:

Mock for Iterator, hashCode: 430126690

But after defIterator.next() invocation I see that though def is an object and not null, it doesn't show hashcode like for Iterator, instead I see this:

com.sun.jdi.InvocationException occurred invoking method.

And after invoking this string:

String columnName = def.getName();

I immediately get NullPointerException like if def is null. What am I doing wrong? Thanks.

EDIT 1 ________________________________________________________________________

I also tried to use PowerMockito with the same methods instead, the result is the same.

EDIT 2 ________________________________________________________________________

I added the whole test method code.


Answer:

It is been a while since this question was created. I have faced this same problem few days ago and I have solved it in the following manner (I hope my proposed solution helps someone in the future):

First of all, I want to clarify that ColumnDefinition.Definition class is a public static nested class that has four private final fields and only has one constructor: Definition (String keyspace, String table, String name and DataType type) (for more details please refer to the ColumnDefinitions.Definition javadoc and ColumnDefinitions source code). Therefore this nested class could not be mocked by Mockito nor Powermock because of its final fields.

SOLUTION:

I had to create a real object, not a mocked one of the class ColumnDefinition.Definition using reflection, so you can initialise the mockDef object as follows:

Constructor<Definition> constructor = (Constructor<Definition>) Definition.class.getDeclaredConstructors()[0]; // as Definition only has one constructor, 0 will be passed as index
constructor.setAccessible(true);
Definition mockDef = constructor.newInstance("keyspace", "table", "name", null);

replacing this line of code in your snippet:

Definition mockDef = Mockito.mock(Definition.class);

Then the NullPointerException will never be thrown again when executing this line of code:

String columnName = def.getName();

Question:

I am new to the Lagom world. I have a scenario to work with unit tests. I work under the Lagom / Java framework and a Cassandra database. I have two different services:

  • Device Service
  • User Service

My need is an intelligent access scenario. A user must register his device to have access authorization. This mechanism is managed by a WBS connect () in the device service. So this WBS deals with:

  • If the device is not available: it stores it in the DB (for security reasons) and does not allow access

  • If the device is registered: it records the date of the access and authorizes the access

My implementation is ready, it works fine. But my question is how to handle this in the unit test side. Especially for the autorized access scenario because for a test start, I do not have a device registered in my DB / persistence.

  • Do I need to invoke a WBS Add () that adds a device to my DB / persistence and then invoke the WBS connect () to simulate the access authorization?
  • Is there a solution to run the WBS connect () without relying on a DB?
  • If my WBS depends on another Service (User service), how to manage the unit test? Do I have to re-implement the User Service in the unit test of the device service?

Answer:

Best I can tell, the Lagom team doesn't believe in traditional unit testing for services; however, there are some unit-style ways to approach testing Lagom services. This is traditionally how testing is prescribed on a "unit" level:

  • Domain object tests
    Testing external commands, events, and proxies
  • Persistent Entity tests
    Testing what happens when your persistent entity attempts to handle entity commands
  • Single service tests
    Tests that your service can handle happy/unhappy paths
  • Message broker tests
    Tests that your service publishes or receives kafka messages

As you probably know, Lagom prescribes a Spring-style API/Impl bifurcation. As a consequence, domain objects tend to fall into the API tests and the others fall into Impl tests. This should make sense from a DDD standpoint.

Without much imagination, you can probably see how extending the single service tests could span to multiple service tests or integration tests.

Question:

Cassandra unit tests works locally but not on jenkins.

edit: I have multiple poms and if i run clean package on the whole project i get the same error. Is this due to different target maps? 1 cassandra.yaml is in test-classes, one in embeddedCassandra and one in the target folder at the bottom of the project in another embedded cassandra folder.

starting cassandra with cu-cassandra.yaml result in the same error.

The cassandra yaml file is located in resources

System.setProperty("cassandra.config", yamlUrl);
EmbeddedCassandraServerHelper.startEmbeddedCassandra("cassandra.yaml");


java.lang.ExceptionInInitializerError: null
    at org.apache.cassandra.config.YamlConfigurationLoader.getStorageConfigURL(YamlConfigurationLoader.java:80)
    at org.apache.cassandra.config.YamlConfigurationLoader.<clinit>(YamlConfigurationLoader.java:94)
    at org.apache.cassandra.config.DatabaseDescriptor.loadConfig(DatabaseDescriptor.java:138)
    at org.apache.cassandra.config.DatabaseDescriptor.<clinit>(DatabaseDescriptor.java:125)
    at org.cassandraunit.utils.EmbeddedCassandraServerHelper.mkdirs(EmbeddedCassandraServerHelper.java:349)
    at org.cassandraunit.utils.EmbeddedCassandraServerHelper.cleanupAndLeaveDirs(EmbeddedCassandraServerHelper.java:321)
    at org.cassandraunit.utils.EmbeddedCassandraServerHelper.startEmbeddedCassandra(EmbeddedCassandraServerHelper.java:122)
    at org.cassandraunit.utils.EmbeddedCassandraServerHelper.startEmbeddedCassandra(EmbeddedCassandraServerHelper.java:91)
    at org.cassandraunit.utils.EmbeddedCassandraServerHelper.startEmbeddedCassandra(EmbeddedCassandraServerHelper.java:70)
    at org.cassandraunit.utils.EmbeddedCassandraServerHelper.startEmbeddedCassandra(EmbeddedCassandraServerHelper.java:66)
    at com.something.connector.HttpConnectorTest.beforeTest(HttpConnectorTest.java:59)

Answer:

This worked for me setting tmp folder that is not the default and set cassandra.config

String folderPath = System.getProperty("user.dir");
        String fileSeparator = System.getProperty("file.separator");
        String path = folderPath + fileSeparator + "target" + fileSeparator + "httpconnector" + fileSeparator
                + "embeddedCassandra";
        URL url = HttpConnectorTest.class.getResource("/cassandra.yaml");
        System.setProperty("cassandra.config", url.toString());

    try {
        EmbeddedCassandraServerHelper.startEmbeddedCassandra("cassandra.yaml", path, 100000);

Question:

I am writing unit-test class using Junit and I am also using power-mocking concept to mock the objects which are created inside the method.

Test Class :

@PowerMockIgnore("javax.management.*")
@RunWith(PowerMockRunner.class)
@PrepareForTest(Client.class)
public class ClientTest {
private static final Logger logger = LoggerFactory
        .getLogger(ClientTest.class);

private static Client client;

private static DetailsDao detailsDao;
public static Session session;
private static IDevicesDao devicesDao;
private static IUserDao userDao;
private static IDao dao;
private static IValidator validator;



@BeforeClass
public static void setup() throws Exception {

    logger.info("*************** Testing ClientTest Started *******************");

    session = Connection.get(); // Here getting error

    detailsDao = mock(DetailsDao.class);
    devicesDao = mock(IDevicesDao.class);
    userDao = mock(UserDao.class);
    validator = mock(IValidator.class);
    dao= mock(IDao.class);

    client = new Client(detailsDao, session, devicesDao, userDao, dao, validator);
}

If I romove @RunWith(PowerMockRunner.class) then its working fine... But I have to run this test using PowerMockRunner only.

Exception :

[10:45:50] sumanth nama: Tests run: 1, Failures: 0, Errors: 1, Skipped: 0,      Time elapsed: 1.234 sec <<< FAILURE!
com.service.clientTest  Time elapsed:       1.234 sec  <<< ERROR!
FSWriteError in target\embeddedCassandra\commitlog\CommitLog-4-1470892233532.log
at    org.apache.cassandra.io.util.FileUtils.deleteWithConfirm(FileUtils.java:135)
at org.apache.cassandra.io.util.FileUtils.deleteRecursive(FileUtils.java:381)
at org.apache.cassandra.io.util.FileUtils.deleteRecursive(FileUtils.java:377)
at org.apache.cassandra.io.util.FileUtils.deleteRecursive(FileUtils.java:377)
at  org.cassandraunit.utils.EmbeddedCassandraServerHelper.rmdir(EmbeddedCassandraSer verHelper.java:266)
at org.cassandraunit.utils.EmbeddedCassandraServerHelper.startEmbeddedCassandra(EmbeddedCassandraServerHelper.java:81)
 at org.cassandraunit.utils.EmbeddedCassandraServerHelper.startEmbeddedCassandra(EmbeddedCassandraServerHelper.java:64)
at org.cassandraunit.utils.EmbeddedCassandraServerHelper.startEmbeddedCassandra(EmbeddedCassandraServerHelper.java:56)
at com.charter.aesd.crossmso.wifi.dao.Connection.get(Connection.java:26)
at com.service.ClientTest.setup(ClientTest.java:76)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.junit.internal.runners.ClassRoadie.runBefores(ClassRoadie.java:57)
at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:122)
at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:106)
at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53)
at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:59)
at o rg.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:252)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:141)
at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:112)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75)
Caused by: java.nio.file.FileSystemException:    target\embeddedCassandra\commitlog\CommitLog-4-1470892233532.log: The process    cannot access the file because it is being used by another process.

I am not getting ... why it is not able to create cassandra session using power mock runner....


Answer:

Mocked the session also, then it runs without any errors.

replaced

session = Connection.get();

with

session = mock(Session.class);