So, I have the following method which is faking a database locally:
public class TestClassDao implements ClassDao {
// ...
private static List<ClassDto> classes = new ArrayList<>();
#Override
public List<ClassDto> getClassesByIds(List<Long> classIds) {
List<ClassDto> results = new ArrayList<>();
for (ClassDto classInstance : classes) {
if (classIds.contains(classInstance.getId())) {
results.add(classInstance);
}
}
return cloner.deepClone(results);
}
//...
}
I was puzzled, because the results were always coming back empty. I stepped through the debugger in Android Studio, and found that the contains check is always returning false even when the right ID is known to be present.
Tracing that back with the debugger, I found what I suspect to be the culprit: according to the debugger, List<Long> classIds contains *Integer* objects. What gives? I'm not sure how to debug this any further.
EDIT:
Here's the debugger output the question is based on:
EDIT 2:
Here's how the test data is being loaded into the data store, you can see I am correctly passing Long values:
The below method is called by a method which does a similar thing for schools, and then persisted via a method in the test DAO.
public static ClassDto getClassTestData(int classId) {
ClassDto classDto = new ClassDto();
switch (classId) {
case 1:
classDto.setId(1L);
classDto.setName("207E - Mrs. Randolph");
classDto.setTeacher(getTeacherTestData());
classDto.setStudents(getStudentsTestData());
return classDto;
case 2:
classDto.setId(2L);
classDto.setName("209W - Mr. Burns");
classDto.setTeacher(getTeacherTestData());
return classDto;
case 3:
classDto.setId(3L);
classDto.setName("249E - Mr. Sorola");
classDto.setTeacher(getTeacherTestData());
return classDto;
default:
return null;
}
}
EDIT 3:
Here is the DAO where the school information is being persisted/retrieved from. The problem is occuring somewhere between the time that the data is inserted and the time it is removed. It goes in with type Long and comes out with Type Int
#Dao
public interface SchoolDao {
#Query("SELECT * FROM schools")
List<SchoolDto> getAllSchools();
#Insert
void insertSchool(SchoolDto schoolDto);
}
Wow, what a nightmare. I have found the culprit.
I had created a TypeConverter to turn a List<Integer> to into a string (and back) so that it can be stored in a single column in the DB in room without having to modify the existing DTOs. However, when I switched over to using Long types as IDs, I failed to convert a single generic argument below in the converter; look carefully at the following code:
public class IdsListConverter {
#TypeConverter
public List<Long> idsFromString(String value) {
Gson gson = new Gson();
if (value == null || value.isEmpty()) {
return null;
} else {
Type resultType = new TypeToken<List<Integer>>(){}.getType();
return gson.fromJson(value, resultType);
}
}
#TypeConverter
public String idsToString(List<Long> ids) {
if (ids == null) {
return null;
} else {
Gson gson = new Gson();
return gson.toJson(ids);
}
}
}
It looks like you found your problem:
Type resultType = new TypeToken<List<Integer>>(){}.getType();
return gson.fromJson(value, resultType);
(in a method returning List<Long>) whereas it should have been:
Type resultType = new TypeToken<List<Long>>(){}.getType();
There is a type-safe way to write this which would have picked up the problem at compile time:
TypeToke<List<Integer>> resultTypeToken = new TypeToken<List<Integer>>() {};
return gson.getAdapter(resultTypeToken).fromJson(value);
This wouldn't have compiled, because the return statement's type is incompatible with the method's return type.
It might be worth looking for other occurrences of fromJson so you can migrate them and see if there are other problems you haven't found yet!
You look at wrong variables. ClassDao instance is below, you can see "{Long#6495} "1". But the Integer "1" you spread is the element of ClassIds which is omitted in your code. You are sure ClassIds is List(), when adding element, you should do classIds.add(new Long(1)).
For future reference, this list of casting rules will help you. In essence, I believe there is/was an implicit casting conflict.
byte –> short –> int –> long –> float –> double
Related
I'm not so good at java and I'm trying to figure out how to fix this issue.
This is my code :
final Method method1 = method;
final Object o = object;
LongSupplier longsupplier = new LongSupplier()
{
private boolean disabled = false;
public long getAsLong()
{
if (this.disabled)
{
return -1L;
}
else
{
try
{
return (long) method1.invoke(o);
}
catch (Throwable throwable)
{
Config.warn("" + throwable.getClass().getName() + ": " + throwable.getMessage());
this.disabled = true;
return -1L;
}
}
}
};
return longsupplier;
The issue is that in the return (long) method1.invoke(o); it say this error : Cannot cast from Object to long.
The code feels indicative of bad java code (java isn't dynamic, don't try to treat it as some sort of javascript or python. There are solutions to this such as SPI, factories, etc). However, if you insist on continuing with it: You'd cast to Long, not long. Then you can just return that (the compiler will figure it out and auto-unbox it), or if you want to do that by hand too, call .longValue() on that.
Java is a typed and not an untyped language for example javascript, although the name may be similar. Therefore, it should only be used in this way. Method is not a valid type, so no type conversion to (long) can be implemented. Therefore there are two "simple" possibilities either you build a new class, which can/is also a new type or you get the result of a method. Unless Method is a class you create, this won't work.
https://docs.oracle.com/cd/E57471_01/bigData.100/extensions_bdd/src/cext_transform_typing.html
I have a third party enum class like this:
package se.api;
public enum InvestigationResultStatus {
PENDING("PendingResult.rr"),
NEW("NewResult.rr"),
MODIFIED("ModifiedResult.rr"),
FINAL("FinalResult.rr"),
PRELIMINARY("PreliminaryResult.rr"),
ADDITIONAL("AdditionalResult.rr"),
REJECTED("RejectedResult.rr"),
COMPLETE("Path.Results.InvestigationInformation.Complete"),
UNDEFINED("");
private final String languageKey;
private InvestigationResultStatus(String languageKey) {
this.languageKey = languageKey;
}
public String getLanguageKey() {
return this.languageKey;
}
}
and in my code I create enum for this class
package se.dto;
public enum InvestigationResultStatus
{
PENDING,
NEW,
MODIFIED,
FINAL,
PRELIMINARY,
ADDITIONAL,
REJECTED,
UNDEFINED
}
to map these api enum to my enum i created enum mapper:
package se.mapper;
import se.dto.InvestigationResultStatus;
public class InvestigationResultStatusMapper
{
public InvestigationResultStatus mapOmResultStatusToNovaResultStatus(final se.api.InvestigationResultStatus investigationResultStatus){
switch (investigationResultStatus){
case PENDING:
return InvestigationResultStatus.PENDING;
case NEW:
return InvestigationResultStatus.NEW;
case MODIFIED:
return InvestigationResultStatus.MODIFIED;
case FINAL:
return InvestigationResultStatus.FINAL;
case PRELIMINARY:
return InvestigationResultStatus.PRELIMINARY;
case ADDITIONAL:
return InvestigationResultStatus.ADDITIONAL;
case REJECTED:
return InvestigationResultStatus.REJECTED;
case UNDEFINED:
return InvestigationResultStatus.UNDEFINED;
default:
throw new IllegalArgumentException("Unknown InvestigationResultStatus: " + investigationResultStatus);
}
}
}
Now I want to test the InvestigationResultStatusMapper class default case path and throw IllegalArgumentException. I search and try it in many ways.But mosta of the examples are in using powermockito.but i want mackito with testNg.How can I test it.I try it using this,
#Test(expectedExceptions = { IllegalArgumentException.class })
public void testMapOmResultStatusToNovaResultStatus_whenHaveDefaultValue_thenThrowIllegalArgumentException()
{
se.api.InvestigationResultStatus investigationResultStatusNewEnum = mock(se.api.InvestigationResultStatus.class);
Whitebox.setInternalState(investigationResultStatusNewEnum, "name", "DEFAULT");
Whitebox.setInternalState(investigationResultStatusNewEnum, "ordinal", "DefaultResult.rr");
se.api.InvestigationResultStatus investigationResultStatusCosmic = mock(se.api.InvestigationResultStatus.class);
when(investigationResultStatusCosmic.values()).thenReturn(
new se.api.InvestigationResultStatus[] { InvestigationResultStatus.PENDING, InvestigationResultStatus.NEW,
se.api.InvestigationResultStatus.MODIFIED, InvestigationResultStatus.FINAL, InvestigationResultStatus.PRELIMINARY,
se.api.InvestigationResultStatus.ADDITIONAL, InvestigationResultStatus.REJECTED,
se.api.InvestigationResultStatus.COMPLETE, InvestigationResultStatus.UNDEFINED, investigationResultStatusNewEnum });
investigationResultStatusMapper.mapOmResultStatusToNovaResultStatus(investigationResultStatusNewEnum);
}
you can create directly an instance in order to avoid mocks.
#Test(expectedExceptions = { IllegalArgumentException.class })
public void testMapOmResultStatusToNovaResultStatus_whenHaveDefaultValue_thenThrowIllegalArgumentException()
{
InvestigationResultStatus investigation = new InvestigationResultStatus();
investigation.mapOmResultStatusToNovaResultStatus(-10000);
....
}
In this I'm unabale to mock enum(final) class using mockito
#BeforeClass
public void setUp()
{
investigationResultStatusMapper = new InvestigationResultStatusMapper();
investigationResultStatusNewEnum = PowerMockito.mock(InvestigationResultStatus.class);
Whitebox.setInternalState(investigationResultStatusNewEnum, "name", "TEST");
Whitebox.setInternalState(investigationResultStatusNewEnum, "ordinal", 9);
InvestigationResultStatus[] investigationResultStatuses = Arrays
.copyOf(InvestigationResultStatus.values(), InvestigationResultStatus.values().length + 1);
investigationResultStatuses[investigationResultStatuses.length - 1] = investigationResultStatusNewEnum;
PowerMockito.mockStatic(InvestigationResultStatus.class);
PowerMockito.when(InvestigationResultStatus.values()).thenReturn(
investigationResultStatuses);
}
/**
* Test Method for {#link InvestigationResultStatusMapper#mapOmResultStatusToNovaResultStatus(InvestigationResultStatus)}
* extend the InvestigationResultStatus enum for DEFAULT throw {#link IllegalArgumentException})
*/
#Test(expectedExceptions = {
IllegalArgumentException.class }, expectedExceptionsMessageRegExp = "Unknown InvestigationResultStatus: TEST")
public void testMapOmResultStatusToNovaResultStatus_whenHaveDefaultValue_thenThrowIllegalArgumentException()
{
investigationResultStatusMapper.mapOmResultStatusToNovaResultStatus(investigationResultStatusNewEnum);
}
Wrong approach. First of all, the 3rd party enum has 9 entries, but your own enum has only 8. So when your mapping code receives COMPLETE it will throw that exception! But if your own enum would have 9 entries, and you just map them 1-1 ... what is the point of using your own enum here in the first place? (there might be good reasons to have it, but at this point, it doesn't add much value).
Beyond that problem, you should do this completely different:
You put these mappings into a Map object. Then write a unit tests that uses InvestigationResultStatus.values() to acquire an array with all valid InvestigationResultStatus constants. You make sure that your map knows how to map all these valid constants (for example by checking that you get a non-null return value). Additionally, you might have one test for each 3rd party constant to check for the expected result.
The key point here is: unfortunately, enums might change over time. So you absolutely want to know when additional constants are added to the 3rd enum.
In other words: the java language respectively the compiler makes sure that there can't be "invalid" instances of that 3rd party enum. When you have InvestigationResultStatus someEnumValue, then it is 100% clear that: either someValue is null, or it is one of the constants from that enum. Nothing else is possible here! Thus: no need to expect, check or handle "invalid" values.
I've got a class like the following:
class A
{
public method doSomething()
{
//....
DAO dataAccessor = new DAO();
List<Object> result1 = dataAccessor.getData(dataAccessor.getSql1());
List<Object> result2 = dataAccessor.getData(dataAccessor.getSql2());
//.. do some stuff with the results
}
Now, I use jMockit for testing the above function, by mocking the DAO class.
This is how my test class looks like:
class A_Test
{
private A myAClass;
#Mocked DAO mockedDAO;
List<Object> resultToSql1, resultToSql2;
// ... Some initializations...
#Test
public void testDoSomething()
{
new NonStrictExpectations()
{
mockedDAO.getSql1(); result = "SQL1";
mockedDAO.getData(withEqual("SQL1")); result = resultToSql1;
mockedDAO.getSql2(); result = "SQL2";
mockedDAO.getData(withEqual("SQL2")); result = resultToSql2;
};
myAClass.doSomething();
}
}
Now, it seems that the second expectation regarding getData() masks the first one, i.e. the mock object behaves as if I never declared the first lines in the expectation (the ones that handle sql1):
The first call to getData() returns empty collection, instead of the values with which I initialized resultToSql1. The second call returns resultToSql2, as expected.
If I comment the following line:
mockedDAO.getData(withEqual("SQL2")); result = resultToSql2;
the first call is returning what I defined - resultToSql1, and the second returns empty collection.
This makes sense.
So, what am I doing wrong? ?How can I define two different return values from getData() based on the parameters of the call?
Any help would be appreciated.
Thanks!
So, After digging more deeply inside the manual, I found that:
...But what if a test needs to decide the result of a recorded invocation based on the arguments it will receive at replay time? We can do it through a mockit.Delegate instance ...
So, in order to solve the above problem, the expectations block should look like this:
new NonStrictExpectations()
{
mockedDAO.getSql1(); result = "SQL1";
mockedDAO.getSql2(); result = "SQL2";
mockedDAO.getData(anyString);
result = new mockit.Delegate()
{
List<Object> getData(String sql)
{
if (sql.equals("SQL1"))
return resultToSql1;
if (sql.equals("SQL2"))
return resultToSql2;
return null;
}
}
};
I'm looking for a Google Collections method that returns the first result of a sequence of Suppliers that doesn't return null.
I was looking at using Iterables.find() but in my Predicate I would have to call my supplier to compare the result against null, and then have to call it again once the find method returned the supplier.
Given your comment to Calm Storm's answer (the desire not to call Supplier.get() twice), then what about:
private static final Function<Supplier<X>, X> SUPPLY = new Function<....>() {
public X apply(Supplier<X> in) {
// If you will never have a null Supplier, you can skip the test;
// otherwise, null Supplier will be treated same as one that returns null
// from get(), i.e. skipped
return (in == null) ? null : in.get();
}
}
then
Iterable<Supplier<X>> suppliers = ... wherever this comes from ...
Iterable<X> supplied = Iterables.transform(suppliers, SUPPLY);
X first = Iterables.find(supplied, Predicates.notNull());
note that the Iterable that comes out of Iterables.transform() is lazily-evaluated, therefore as Iterables.find() loops over it, you only evaluate as far as the first non-null-returning one, and that only once.
You asked for how to do this using Google Collections, but here's how you would do it without using Google Collections. Compare it to Cowan's answer (which is a good answer) -- which is easier to understand?
private static Thing findThing(List<Supplier<Thing>> thingSuppliers) {
for (Supplier<Thing> supplier : thingSuppliers) {
Thing thing = supplier.get();
if (thing != null) {
return thing;
}
}
// throw exception or return null
}
In place of the comment -- if this was the fault of the caller of your class, throw IllegalArgumentException or IllegalStateException as appropriate; if this shouldn't have ever happened, use AssertionError; if it's a normal occurrence your code that invokes this expects to have to check for, you might return null.
What is wrong with this?
List<Supplier> supplierList = //somehow get the list
Supplier s = Iterables.find(supplierList, new Predicate<Supplier>(){
boolean apply(Supplier supplier) {
return supplier.isSomeMethodCall() == null;
}
boolean equals(Object o) {
return false;
}
});
Are you trying to save some lines? The only optimisation I can think is to static import the find so you can get rid of "Iterables". Also the predicate is an anonymous inner class, if you need it in more than one place you can create a class and it would look as,
List<Supplier> supplierList = //somehow get the list
Supplier s = find(supplierList, new SupplierPredicateFinder());
Where SupplierPredicateFinder is another class.
UPDATE : In that case find is the wrong method. You actually need a custom function like this which can return two values. If you are using commons-collections then you can use a DefaultMapEntry or you can simply return an Object[2] or a Map.Entry.
public static DefaultMapEntry getSupplier(List<Supplier> list) {
for(Supplier s : list) {
Object heavyObject = s.invokeCostlyMethod();
if(heavyObject != null) {
return new DefaultMapEntry(s, heavyObject);
}
}
}
Replace the DefaultMapEntry with a List of size 2 or a hashmap of size 1 or an array of length 2 :)
This might seem like a pretty detailed question about Easymock, but I'm having a hard time finding a support site/forum/mailing list for this library.
I'm encountering a bug when using the captures() method that seems to return the captured parameters out of order.
Here's a simplified version of what I am testing:
public class CaptureTest extends TestCase {
// interface we will be mocking
interface Processor {
void process(String x);
}
// class that uses the interface above which will receive the mock
class Component {
private Processor processor;
private String[] s = { "one", "two", "three", "four" };
Component(Processor processor) {
this.processor = processor;
}
public void doSomething() {
for (int i = 0; i < s.length; i++) {
processor.process(s[i]);
}
}
}
public void testCapture() {
//create the mock, wire it up
Processor mockProcessor = createMock(Processor.class);
Component component = new Component(mockProcessor);
//we're going to call the process method four times
//with different arguments, and we want to capture
//the value passed to the mock so we can assert against it later
Capture<String> cap1 = new Capture<String>();
Capture<String> cap2 = new Capture<String>();
Capture<String> cap3 = new Capture<String>();
Capture<String> cap4 = new Capture<String>();
mockProcessor.process(and(isA(String.class), capture(cap1)));
mockProcessor.process(and(isA(String.class), capture(cap2)));
mockProcessor.process(and(isA(String.class), capture(cap3)));
mockProcessor.process(and(isA(String.class), capture(cap4)));
replay(mockProcessor);
component.doSomething();
//check what values were passed to the mock
assertEquals("one", cap1.getValue());
assertEquals("two", cap2.getValue());
assertEquals("three", cap3.getValue());
assertEquals("four", cap4.getValue());
verify(mockProcessor);
}
}
(Please note that this is just a simplified test case - I know that I could specify the exact value of the arguments I expect passed to my mock, but in my real case the arguments are complex objects with a handful of fields, and I want to capture the object so I can assert against just a few of those fields without re-creating the entire object in my test case).
When I run the test, it fails at:
junit.framework.ComparisonFailure: expected:<[one]> but was:<[four]>
Meaning that the parameter that EasyMock is capturing in cap1 is not the first call to the method, but the last (since the value is four). I get the same results if I reverse the captures() declarations, i.e. use cap4 with the first method call, etc.
This seems like it might be a bug within EasyMock - different parameters passed to the same method in different invocations don't seem to be capture correctly.
Is anyone else using capture() with EasyMock and having similar problems? Is there an easy workaround you know of, or a different way I can capture the parameters being passed to my mock's methods?
Update 1: fixed code sample to show I am using createMock, not createStrictMock, but I get the same error with both (although the actual value of what is captured changes).
I've received an answer on the bug I submitted to the Easymock sourceforge site, and a developer has confirmed it is indeed a bug with this version of Easymock.
It is indeed a bug. The capture is done even if it was already done. The
current workaround is to implement your own capture object and override
setValue to do this:
#Override
public void setValue(T value) {
if(!hasCaptured()) {
super.setValue(value);
}
}
I was playing around with your test and could not solve.
However I extended the Capture Class to see if the values were set in a different order (I was suspicious that EasyMock internally was using a hash with a key generated from the methods and the parameters) I was wrong the methods are set in the correct order. But there is something really weird going on.. It seems that the algorithm does some kind assigning pattern.. Well let me show the code and the strange output.... BTW the changes from mock, niceMock and strictMock didn't make anydifference..
class MyCapture extends Capture<String> {
private String id;
public MyCapture(String id) {
super();
System.out.printf("Constructor %s expecting %s\n", id, this.getClass().getName());
this.id = id;
}
private static final long serialVersionUID = 1540983654657997692L;
#Override
public void setValue(String value) {
System.out.printf("setting value %s expecting %s \n", value, id);
super.setValue(value);
}
#Override
public String getValue() {
System.out
.printf("getting value %s expecting %s \n", super.getValue(), id);
return super.getValue();
}
}
public void testCapture() {
// create the mock, wire it up
Processor mockProcessor = createStrictMock(Processor.class);
Component component = new Component(mockProcessor);
// we're going to call the process method four times
// with different arguments, and we want to capture
// the value passed to the mock so we can assert against it later
Capture<String> cap1 = new MyCapture("A");
Capture<String> cap2 = new MyCapture("B");
Capture<String> cap3 = new MyCapture("C");
Capture<String> cap4 = new MyCapture("D");
mockProcessor.process(and(isA(String.class), capture(cap1)));
mockProcessor.process(and(isA(String.class), capture(cap2)));
mockProcessor.process(and(isA(String.class), capture(cap3)));
mockProcessor.process(and(isA(String.class), capture(cap4)));
replay(mockProcessor);
component.doSomething();
// check what values were passed to the mock
assertEquals("A", cap1.getValue());
assertEquals("B", cap2.getValue());
assertEquals("C", cap3.getValue());
assertEquals("D", cap4.getValue());
verify(mockProcessor);
}
}
*And this is the output *
Constructor A expecting com.comp.core.dao.impl.CaptureTest$MyCapture
Constructor B expecting com.comp.core.dao.impl.CaptureTest$MyCapture
Constructor C expecting com.comp.core.dao.impl.CaptureTest$MyCapture
Constructor D expecting com.comp.core.dao.impl.CaptureTest$MyCapture
calling process A
setting value A expecting A
calling process B
setting value B expecting A <<Setting the wrong guy
setting value B expecting A <<Setting the wrong guy
setting value B expecting B <<Ops this is the right one..stop
calling process C
setting value C expecting B <<Setting the wrong guy
setting value C expecting B <<Setting the wrong guy
setting value C expecting C <<Setting the wrong guy
calling process D
setting value D expecting C <<Setting the wrong guy
setting value D expecting C <<Setting the wrong guy
setting value D expecting D <<Ops this is the right one..stop
getting value B expecting A
Sorry I can't help you more. It might be indeed a bug in easy mock.
You can also try using EasyMock.createNiceMock(...) instead of EasyMock.createStrictMock(...) or EasyMock.createMock(...).
Although, I agree that it looks more like a bug with createMock.
This is a problem more appropriate for state-based testing, I think.
With JMockit, you could solve it like this:
import mockit.*;
import static mockit.Mockit.*;
import mockit.integration.junit3.*;
public class CaptureTest extends JMockitTestCase
{
interface Processor { void process(String x); }
class Component
{
private final Processor processor;
private final String[] s = {"one", "two", "three", "four"};
Component(Processor processor) { this.processor = processor; }
public void doSomething()
{
for (String value : s) {
processor.process(value);
}
}
}
#MockClass(realClass = Processor.class)
static class MockProcessor
{
private final String[] expectedValues;
private int i;
MockProcessor(String... expectedValues) { this.expectedValues = expectedValues; }
#Mock
void process(String x)
{
assertEquals(expectedValues[i++], x);
}
}
public void testCapture()
{
Processor mockProcessor = setUpMock(new MockProcessor("one", "two", "three", "four"));
Component component = new Component(mockProcessor);
component.doSomething();
}
}
In short, here's what worked for me:
MyClass myMock = EasyMock.createStrictMock(MyClass.class);
...
EasyMock.checkOrder(myMock, true); // before the capture and verify, not sure if it matters
...
Capture<MyArg> capturedArgs = new Capture<MyArg>();
expect(myMock.search(capture(capturedArgs))).andReturn(someRandomReturn);
PS: I'm using EasyMock 3.0
Instead of calling EasyMock.createStrictMock(...) just call EasyMock.createMock(...). Should solve your problems.