Neo4jOperations#queryForObjects() doesn't seem to play well with #QueryResult POJOs - it always says that result set is empty.
Trying Neo4jOperations#queryForObjects - it says result is empty:
#Test
public void thisDoesNotWork() {
Iterable<ClassNodeIdAndName> result = neo4jOperations.queryForObjects(
ClassNodeIdAndName.class,
"MATCH (c:ClassNode) RETURN ID(c) AS id, c.name AS name",
new HashMap<>());
assertTrue(result.iterator().hasNext());
}
Trying Neo4jOperations#query - says result is NOT empty:
#Test
public void thisWorksFine() {
Result result = neo4jOperations.query(
"MATCH (c:ClassNode) RETURN ID(c) AS id, c.name AS name",
new HashMap<>());
assertTrue(result.iterator().hasNext());
}
Trying repository with #Query - says result is NOT empty:
#Test
public void thisWorksFineAsWell() {
List<ClassNodeIdAndName> classNodeIdsAndNames = classNodeRepository.getAllIdsAndNames();
assertFalse(classNodeIdsAndNames.isEmpty());
}
public interface ClassNodeRepository extends GraphRepository<ClassNode> {
#Query("MATCH (c:ClassNode) RETURN ID(c) AS id, c.name AS name")
List<ClassNodeIdAndName> getAllIdsAndNames();
}
#QueryResult
public class ClassNodeIdAndName {
public Long id;
public String name;
}
Documentation says that
Iterable queryForObjects(Class entityType,
entityType - The Class denoting the type of entity to return
But I'm confused whether I should look at type of entity or at for objects. If it's not supposed to handle #QueryResult, I would expect it to throw instead of returning no results.
I'm using spring-data-neo4j 4.1.3.RELEASE
#QueryResult is a Spring Data Neo4j concept that applies only to Spring Repositorys.
Neo4jOperations is a thin wrapper around the Neo4j OGM's Session class and consequently does not handle the concept of returning query result objects.
Also see: SDN 4 Session.query doesn't work for #QueryResult
I have an entity that has a List object. I can see the object that currently contain one element. However, when I tried to retrieve the list, I always get null.
There are three classes: two entity classes and an endpoint class
public class Buddy{
...
#Persistent (mappedBy="owner")
#Order (extensions = #Extension(vendorName="datanucleus",key="list-ordering", value="sharedOn desc"))
#Element(dependent = "true")
#JsonManagedReference
private List<Sticky> listOfObjects;
...
public List<Sticky> getStickies(){
return listOfObjects;
}
}
public Class Sticky{
...
#Persistent (dependent="true")
#JsonBackReference
private Buddy owner;
...
public Buddy getBuddy(){
return this.owner;
}
...
}
public class StickyEndpoint{
...
#ApiMethod(name = "createSticky")
public Sticky createSticky(Sticky sticky){
Buddy buddy = sticky.getBuddy(); // confirmed that buddy returned is not null
List<Sticky> sticky = buddy.getStickies(); //sticky always return null
...
return sticky;
}
....
}
Can someone help? Thanks!
JDO will not let u insert custom type, so List will not run. I ended up installing Objectify....
I have the following simple DynamoDBDao which contains one method that queries an index and returns a map of results.
import com.amazonaws.services.dynamodbv2.document.*;
public class DynamoDBDao implements Dao{
private Table table;
private Index regionIndex;
public DynamoDBDao(Table table) {
this.table = table;
}
#PostConstruct
void initialize(){
this.regionIndex = table.getIndex(GSI_REGION_INDEX);
}
#Override
public Map<String, Long> read(String region) {
ItemCollection<QueryOutcome> items = regionIndex.query(ATTR_REGION, region);
Map<String, Long> results = new HashMap<>();
for (Item item : items) {
String key = item.getString(PRIMARY_KEY);
long value = item.getLong(ATTR_VALUE);
results.put(key, value);
}
return results;
}
}
I am trying to write a unit test which verifies that when the DynamoDB index returns an ItemCollection then the Dao returns the corresponding results map.
public class DynamoDBDaoTest {
private String key1 = "key1";
private String key2 = "key2";
private String key3 = "key3";
private Long value1 = 1l;
private Long value2 = 2l;
private Long value3 = 3l;
#InjectMocks
private DynamoDBDao dynamoDBDao;
#Mock
private Table table;
#Mock
private Index regionIndex;
#Mock
ItemCollection<QueryOutcome> items;
#Mock
Iterator iterator;
#Mock
private Item item1;
#Mock
private Item item2;
#Mock
private Item item3;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
when(table.getIndex(DaoDynamo.GSI_REGION_INDEX)).thenReturn(regionIndex);
dynamoDBDao.initialize();
when(item1.getString(anyString())).thenReturn(key1);
when(item1.getLong(anyString())).thenReturn(value1);
when(item2.getString(anyString())).thenReturn(key2);
when(item2.getLong(anyString())).thenReturn(value2);
when(item3.getString(anyString())).thenReturn(key3);
when(item3.getLong(anyString())).thenReturn(value3);
}
#Test
public void shouldReturnResultsMapWhenQueryReturnsItemCollection(){
when(regionIndex.query(anyString(), anyString())).thenReturn(items);
when(items.iterator()).thenReturn(iterator);
when(iterator.hasNext())
.thenReturn(true)
.thenReturn(true)
.thenReturn(true)
.thenReturn(false);
when(iterator.next())
.thenReturn(item1)
.thenReturn(item2)
.thenReturn(item3);
Map<String, Long> results = soaDynamoDbDao.readAll("region");
assertThat(results.size(), is(3));
assertThat(results.get(key1), is(value1));
assertThat(results.get(key2), is(value2));
assertThat(results.get(key3), is(value3));
}
}
My problem is that items.iterator() does not actually return Iterator it returns an IteratorSupport which is a package private class in the DynamoDB document API. This means that I cannot actually mock it as I did above and so I cannot complete the rest of my test.
What can I do in this case? How do I unit test my DAO correctly given this awful package private class in the DynamoDB document API?
First, unit tests should never try to verify private state internal to an object. It can change.
If the class does not expose its state via non-private getter methods, then it is none of your test's business how it is implemented.
Second, why do you care what implementation the iterator has?
The class has fulfilled its contract by returning an iterator (an interface)
which when iterated over will return the objects it is supposed to.
Third, why are you mocking objects that you don't need to?
Construct the inputs and outputs for your mocked objects, don't mock them; it is unnecessary.
You pass a Table into your constructor? Fine.
Then extend the Table class to make whatever protected methods for whatever you need.
Add protected getters and/or setters to your Table subclass.
Have them return hard coded values if necessary. They don't matter.
Remember, only test one class in your test class.
You are testing the dao not the table nor the index.
Dynamodb api has a lot of such classes which can not easily be mocked. This results in lot of time spent on writing complex tests and changing features are big pain.
I think, for this case a better approach will be not try to go the traditional way and use DynamodbLocal library by the AWS team - http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Tools.DynamoDBLocal.html
This is basically an in memory implementation of DyanamoDB. We had written our tests such that during unit test initialization, DyanmodbLocal instance would be spawned and tables would be created. This makes the testing a breeze. We have not yet found any bugs in the library and it is actively supported and developed by AWS. Highly recommend it.
One possible workaround is to define a test class which extends IteratorSupport in the same package that it is present in, and define the desired behavior
You can then return an instance of this class through your mock setup in the test case.
Of course, this is not a good solution, but simply a workaround for the same reasons that #Jeff Bowman mentioned in the comment.
May be it'd be better to extract ItemCollection retrieval to the separate method?
In your case it may look as follows:
public class DynamoDBDao {
protected Iterable<Item> readItems(String region) { // can be overridden/mocked in unit tests
// ItemCollection implements Iterable, since ItemCollection-specific methods are not used in the DAO we can return it as Iterable instance
return regionIndex.query(ATTR_REGION, region);
}
}
then in unit tests:
private List<Item> mockItems = new ArrayList<>(); // so you can set these items in your test method
private DynamoDBDao dao = new DynamoDBDao(table) {
#Override
protected Iterable<Item> readItems(String region) {
return mockItems;
}
}
When you use when(items.iterator()).thenReturn(iterator); Mockito sees the items as ItemCollection which causes the compilation error. In your test case, you want to see ItemCollection as just an Iterable. So, the simple solution is to cast the items as Iterable like below:
when(((Iterable<QueryOutcome>)items).iterator()).thenReturn(iterator);
Also make your iterator as
#Mock
Iterator<QueryOutcome> iterator;
This should fix the code without warning :)
If this fixes the problem, please accept the answer.
You can test your read method by using fake objects like this :
public class DynamoDBDaoTest {
#Mock
private Table table;
#Mock
private Index regionIndex;
#InjectMocks
private DynamoDBDao dynamoDBDao;
public DynamoDBDaoTest() {
}
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
when(table.getIndex(GSI_REGION_INDEX)).thenReturn(regionIndex);
dynamoDBDao.initialize();
}
#Test
public void shouldReturnResultsMapWhenQueryReturnsItemCollection() {
when(regionIndex.query(anyString(), anyString())).thenReturn(new FakeItemCollection());
final Map<String, Long> results = dynamoDBDao.read("region");
assertThat(results, allOf(hasEntry("key1", 1l), hasEntry("key2", 2l), hasEntry("key3", 3l)));
}
private static class FakeItemCollection extends ItemCollection<QueryOutcome> {
#Override
public Page<Item, QueryOutcome> firstPage() {
return new FakePage();
}
#Override
public Integer getMaxResultSize() {
return null;
}
}
private static class FakePage extends Page<Item, QueryOutcome> {
private final static List<Item> items = new ArrayList<Item>();
public FakePage() {
super(items, new QueryOutcome(new QueryResult()));
final Item item1= new Item();
item1.with(PRIMARY_KEY, "key1");
item1.withLong(ATTR_VALUE, 1l);
items.add(item1);
final Item item2 = new Item();
item2.with(PRIMARY_KEY, "key2");
item2.withLong(ATTR_VALUE, 2l);
items.add(item2);
final Item item3 = new Item();
item3.with(PRIMARY_KEY, "key3");
item3.withLong(ATTR_VALUE, 3l);
items.add(item3);
}
#Override
public boolean hasNextPage() {
return false;
}
#Override
public Page<Item, QueryOutcome> nextPage() {
return null;
}
}
ItemCollection<QueryOutcome> items = new ItemCollection<QueryOutcome>() {
#Override
public Integer getMaxResultSize() {
return 0;
}
#Override
public Page<Item, QueryOutcome> firstPage() {
return null;
}
};
Mockito.when(index.query(Mockito.any(QuerySpec.class))).thenReturn(items);
QueryResult queryResult = new QueryResult();
Mockito.when(dynamoDBClient.query(Mockito.any(QueryRequest.class))).thenReturn(queryResult);
I'm trying to test a domain class called EnityContact. Inside that class there is a method called initialize which populates some fields when needed. in order to do that the method creates instances of some other domain classes: AisUser, Entity and CPerson. AisUser is the domain class returned by the call to SecurityUtil.retrieveCurrentAisUser(false).
class EntityContact extends BaseObject implements Initializable{
....
#Override
void initialize() {
println "initaliazing"
isMain = false
creationDate = new Date()
createdBy = CPerson.get(SecurityUtil.retrieveCurrentAisUser(false).id)
entity = new Entity()
entity.setId(Long.valueOf(0)) //Id has to be initialized with some value
}
}
What i am trying to do is find a way to return mocks of those classes that i define in my specification.
Any ideas?
In Groovy you can mock static methods using MetaClass.
SecurityUtil.metaClass.'static'.retrieveCurrentAisUser = { boolean param ->
}
I have the following class that has two static methods Retrieve and RetrieveWithQuery.
Below the classes listed here, I have included a snippet of the test.
All but the last assert of the test fails with the following message:
Failed TestMethod2 MoqTest Assert.AreEqual failed. Expected:. Actual:<(null)>.
I understand that the problem may be that the query that I setup in the mock
is a different instance from the query used in the RetrieveWithQuery method.
And that is why is would be returning null.
In a perfect world I would simply re-factor the service class, unfortunately I am
working with legacy code that is already production. The goal is to first complete
tests, then re-factor code and run regression testing before updating production
environment.
Is there a workaround or different way to test this?
public class MyService
{
public virtual string RetrieveMethod(string account)
{
if (account == "The abc company")
{
return "Peter Smith";
}
return "John Doe";
}
public virtual string RetrieveMethod(MyQuery query)
{
return RetrieveMethod(query.QueryString);
}
public static string Retrieve(MyService service, string value)
{
return service.RetrieveMethod(value);
}
public static string RetrieveWithQuery(MyService service, string value)
{
var query = new MyQuery
{
QueryString = value
};
return service.RetrieveMethod(query);
}
}
public class MyQuery
{
public string QueryString;
}
[TestMethod]
public void TestMethod2()
{
var mockService = new Mock<MyService>();
const string company = "The abc company";
const string expectedContact = "Peter Smith";
var queryAccount = new MyQuery
{
QueryString = company
};
// Setup base retrieve
mockService.Setup(myServ => myServ.RetrieveMethod(company)).Returns(expectedContact);
// Setup base retrieve with query
mockService.Setup(myServ => myServ.RetrieveMethod(queryAccount)).Returns(expectedContact);
// test base retrieve with query - PASS
Assert.AreEqual(expectedContact, mockService.Object.RetrieveMethod(queryAccount));
// test static method retrieve - PASS
Assert.AreEqual(expectedContact, MyService.Retrieve(mockService.Object, company));
// test static method retrieve with query - FAIL
Assert.AreEqual(expectedContact, MyService.RetrieveWithQuery(mockService.Object, company));
}
Try this for your setup:
// Setup base retrieve with query
mockService.Setup(myServ => myServ.RetrieveMethod(It.Is<Query>(q=>q.QueryString == queryAccount.QueryString)).Returns(expectedContact);
Or you could overload on Equals for Query so that the Query that gets created is equal to expectedQuery.
The Moq QuickStart page has good examples of this and more which should help a lot.