Using jmockit 1.2 jar,
Trying to mock String's length method but getting Unexpected Invocation Exception:
FAILED: test
java.lang.IllegalStateException: Missing invocation to mocked type at this point; please make sure such invocations appear only after the declaration of a suitable mock field or parameter
at StringDemo.TestA$1.<init>(TestA.java:17)
at StringDemo.TestA.test(TestA.java:13)
I am using testNG:
#Test
public void test() throws Exception
{
new Expectations()
{
#Mocked("length")
String aString;
{
aString.length();
result = 2;
}
};
System.out.println(A.showA("test"));
}
}
Actual class A:
public class A {
public static int showA(String str){
int a= str.length();
return a;
}
}
This is the wrong way of recording the expected results. You shouldn't mock and record String's length() method, record your showA() instead. here is the solution
#SuppressWarnings("unused")
#Test
public void test() throws Exception
{
new Expectations()
{
#NonStrict
final Source mock = null;
{
Source.showA(anyString);
result = 2;
}
};
assertEquals(2, Source.showA("test"));
}
Related
In class A, i got a function called updateAttribute. In class B, I got a junit test, which stores during execution this function in a Method object (code is simplified).
public class A {
public Optional<AttributeObject> updateAttribute(
#ApiParam("Qual of attribute") #PathParam("qual") #Qual final String qual,
#NotNull #Valid final UpdateObject a) {
// here, I've cut a few lines of code
return null;
}
}
public class ATest extends AnotherTest {
#Test
public void someTest()
throws NoSuchMethodException, SecurityException {
try (
// some code I've cut
final Method method =
A.getClass().getMethod("updateAttribute", String.class, UpdateObject.class);
// some code I've cut
}
}
}
The junit test fails at this call of .getMethod() with:
java.lang.IllegalArgumentException: HV000181: Wrong number of
parameters. Method or constructor
java.util.Optional"<"packageName.A">"#updateAttribute(String,
UpdateObject) expects 1 parameters, but got 2.
(...)
When I change the call to
final Method method =
A.getClass().getMethod("updateAttribute", String.class);
or similar, the trace just claims - as expected - that this method doesn't exist.Any ideas how to fix this?
Not an answer, just content that doesn't fit into a comment.
Reduced the code to this:
#Test
public void someTest()
throws NoSuchMethodException, SecurityException {
final Method method =
A.class.getMethod("updateAttribute", String.class, Integer.class);
}
}
class A {
public Optional<String> updateAttribute(
final String qual, Integer a) {
return null;
}
}
And that works fine.
Not reproducable.
I'm using easymock and powermock to write unit test case for the below isRegisteredUSer() of Class B. How to mock getUserInformation() of Class A and return a mocked UserAccessBean?
class A{
private int userId;
A(int userId){
this.userId = userId;
}
public UserAccessBean getUserInformation(){
UserAccessBean userAB = new USerAccessBean().findByUserId(userId);
return userAB;
}
}
Class B{
public static boolean isRegisteredUSer(int userId){
A a = new A(userId);
UserAccessBean userAB = a.getUserInformation();
if(userAB.getUserType().equals("R")){
return true;
}
return false;
}
JUnit
public class BTest extends EasyMockSupport{
UserAccessBean userAB = null;
A a = null;
int userId = 12345;
#Before
public void setUp() throws Exception {
userAB = new UserAccessBean();
}
#Test
public void when_UserDesctiptionIsR_Expect_True_FromIsRegisteredUser() throws Exception{
//data setup
userAB.setDescription("R");
A a = new A(12345);
EasyMock.expect(a.isRegisteredUser()).andReturn(userAB);
PowerMock.replayAll();
Boolean flag = B.isRegisteredUser(userId);
assertEquals(flag, true);
PowerMock.verifyAll();
}
}
Even If I use EasyMock.expect() to mock getUserInformation() method call, my console is going inside getUserInformation() when I run my JUnit.
Can someone please help me to mock another class functions method (Class A's getUserInformation) call from the method (Class B's isRegisteredUSer) being tested?
Please, next time copy actual working code. Your code has many typos and anomalies that makes it hard to workaround.
Nevertheless, I think you want a normal EasyMock for A and a mock on new for B. The code below should answer your question
#RunWith(PowerMockRunner.class)
#PrepareForTest({A.class, B.class})
public class BTest extends EasyMockSupport {
UserAccessBean userAB = new UserAccessBean();
A a;
int userId = 12345;
#Test
public void when_UserDesctiptionIsR_Expect_True_FromIsRegisteredUser() throws Exception {
//data setup
userAB.setDescription("R");
A a = createMock(A.class);
expect(a.getUserInformation()).andReturn(userAB);
replayAll();
PowerMock.expectNew(A.class, userId).andReturn(a);
PowerMock.replay(A.class);
Boolean flag = B.isRegisteredUser(userId);
assertEquals(flag, true);
PowerMock.verifyAll();
verifyAll();
}
}
I will however highly recommend A to be injected into B and to get rid of the static method. That will get rid of PowerMock and simplify the code.
I have a class which I would like to test with a public static method that contains some chained method calls. Assuming that an exception occurs during the chained method calls, how do I handle this effectively and make it return some specific value?
Following is the code sample of the test class.
#RunWith(PowerMockRunner.class)
#PrepareForTest({CodeWithPrivateMethod.class,CodeWithAnotherPrivateMethod.class,CodeWithYetAnotherPrivateMethod.class})
public class CodeWithPrivateMethodTest {
#Test
public void when_gambling_is_true_then_always_explode() throws Exception {
CodeWithYetAnotherPrivateMethod codeWithYetAnotherPrivateMethod = PowerMockito.spy(new CodeWithYetAnotherPrivateMethod());
PowerMockito.whenNew(CodeWithYetAnotherPrivateMethod.class).withAnyArguments().thenReturn(codeWithYetAnotherPrivateMethod);
CodeWithAnotherPrivateMethod codeWithAnotherPrivateMethod = PowerMockito.spy(new CodeWithAnotherPrivateMethod());
PowerMockito.whenNew(CodeWithAnotherPrivateMethod.class).withAnyArguments().thenReturn(codeWithAnotherPrivateMethod);
PowerMockito.doReturn(true).when(codeWithYetAnotherPrivateMethod, "getGambling");
//PowerMockito.doReturn(codeWithYetAnotherPrivateMethod).when(codeWithAnotherPrivateMethod, "getGambleValue");
PowerMockito.spy(CodeWithPrivateMethod.class);
CodeWithPrivateMethod.startGamble();
}
}
Following is the code sample for the class under test
public class CodeWithPrivateMethod {
public static void startGamble() {
Boolean gamble = CodeWithAnotherPrivateMethod.getGambleValue()
.getGambling();
if (gamble) {
System.out.println("kaboom");
}else{
System.out.println("boom boom");
}
}
}
Following is the code sample for the class that gets called from the class under test
public class CodeWithAnotherPrivateMethod {
static CodeWithYetAnotherPrivateMethod codeWithYetAnotherPrivateMethod = new CodeWithYetAnotherPrivateMethod();
public static CodeWithYetAnotherPrivateMethod getGambleValue() {
return codeWithYetAnotherPrivateMethod; //works fine
return null; // fails
}
}
Following is the code sample for the other class that gets called from the class under test
public class CodeWithYetAnotherPrivateMethod {
public Boolean getGambling() {
return false;
}
}
So Assuming I return a null value from getGambleValue() method of CodeWithAnotherPrivateMethod class, how do I handle this null value effectively in my testclass?
This is how to specify expected exceptions using Mockito:
#Test(expected = NullPointerException.class)
public void when_gambling_is_true_then_always_explode() throws Exception {
...
Before I found out about this I would do:
#Test
public void when_gambling_is_true_then_always_explode() throws Exception {
// setup omitted
try {
CodeWithPrivateMethod.startGamble();
}
catch(NullPointerException e) {
// expected
return;
}
fail("Expected NullPointerException");
}
EDIT: Testing multiple classes that call each other statically like this is a severe code smell. Unit tests should test a single class and inline static calls should be limited to utility classes.
Another comment: your example class names are very confusing. Next time please stick with Foo, Bar, Baz or Appple, Pear, Banana.
If you are not getting an NPE then I expect your mocking/spying is interfering. If you call the code under test without mocking/spying the call chain would be:
CodeWithPrivateMethod.startGamble();
->
CodeWithYetAnotherPrivateMethod value = CodeWithAnotherPrivateMethod.getGambleValue();
->
return null;
<-
value.getGambling();
<- throws NullPointerException
What exactly are you trying to find out or achieve?
EDIT: Here's how it should work with PowerMock
#RunWith(PowerMockRunner.class)
#PrepareForTest(CodeWithAnotherPrivateMethod.class)
public class CodeWithPrivateMethodTest {
#Mock
private CodeWithYetAnotherPrivateMethod yetAnotherInstance;
#Test
public final void testStartGamble() {
// SETUP
mockStatic(CodeWithAnotherPrivateMethod.class);
expect(CodeWithAnotherPrivateMethod.getGambleValue())
.andReturn(yetAnotherInstance);
Boolean gamblingValue = true;
expect(yetAnotherInstance.getGambling()).andReturn(gamblingValue);
replayAll();
// CALL
CodeWithPrivateMethod.startGamble();
// VERIFY
verifyAll();
}
Consider the following code:
#Tested
CodeToTest codeToTest;
#Injectable
Injected injected;
#Test
public void test() {
new Expectations() {{ ... }}
assertThat(codeToTest.memberVariable).isEqualTo("x");
}
//
public class CodeToTest { public CodeToTest(Injected injected) { memberVariable = injected.getProperty("x") } }
I want to test CodeToTest. CodeToTest needs Injected to be injected into it's constructor. How do I set a property such as injected.setProperty("x") so that it is available for access in CodeToTest?
The test at hand should be covering a specific method of CodeToTest; the constructor should have its own tests like your test does. So for example, if the constructor is setting a field according to what gets passed in, like this:
public class Bar {
public int getValue() {
return 8675309;
}
}
public class Foo {
public String field = null;
public Foo(Bar b) {
this.field = "" + b.getValue();
}
public String getField() {
return this.field;
}
public char getFirstChar() {
return getField().charAt(0);
}
}
Here I am setting a String field according to an int found in a Bar that was passed into the constructor. I wish to unit test my getFirstChar() method ...
#Tested Foo foo;
#Injectable Bar bar;
#Test
public void test() throws Exception {
// ...
}
Now, as you point out, in this case my field has already been set before test() even starts. So I have two choices here: Firstly, since I am pulling out the field based on its getter, I can partially mock my class being tested:
#Test
public void test() throws Exception {
new Expectations(foo) {{
foo.getField(); result = "24601";
}};
char c = foo.getFirstChar();
assertThat(c, is('2'));
}
OR, if you don't want to do this or if you are doing direct field access rather than via getter, you can use Deencapsulation (part of JMockit) to set the internal field and then test:
#Test
public void test() throws Exception {
Deencapsulation.setField(foo, "field", "24601");
char c = foo.getFirstChar();
assertThat(c, is('2'));
}
And of course, I test my constructor separately:
#Test
public void testConstructor() throws Exception {
new Expectations() {{
bar.getValue(); result = 24601;
}};
Foo foo2 = new Foo(bar);
String fieldValue = foo2.getField(); // or use Deencapsulation
assertThat(fieldValue, is("24601"));
}
Hope this helps, and good luck!
My question: how to create a mocked object and inject attributes via the constructor or a setter?
I get unexpected invocation errors. I am doing a set on my mock object in #Before to set the name attribute for my BAPI. When i execute the test, I get an unexpected invocation error on my setName method. But, I don't really want to test this method. I'm just plugging it so the value is there when my code executes the method checkParm(b).
If I don't add any expectation for the setter on the mocked I get unexpected invocation. But, also if I add this code to the expectations, I still get unexpected invocation.
ignoring(mockAdapter).setName(BAPI_NAME);
inSequence(sequence);
here's my #Before method
#Before
public void setUp() throws Exception {
objectUnderTest = new ApoSAPExtractor();
mockAdapter = context.mock(BapiAdapter.class);
mockAdapter.setName(BAPI_NAME);
apoResults = new ApoResults();
apoParameterBean = new ApoParameterBean();
}
Then my test method:
#Test
public final void testExtract() throws Exception {
final Sequence sequence = context.sequence(SEQUENCE);
context.checking(new Expectations() {{
atLeast(1).of(mockAdapter).getName();
will(returnValue(new String()));
inSequence(sequence);
oneOf(mockAdapter).activate();
inSequence(sequence);
oneOf(mockAdapter).getImportTableParameter(IM_PARMS);
inSequence(sequence);
will(returnValue(JCoTable.class));
oneOf(mockAdapter).execute();
inSequence(sequence);
oneOf(mockAdapter).getExportTableAdapter(EX_PO_APO);
inSequence(sequence);
will(returnValue(new TableAdapter(with(any(JCoTable.class)))));
}});
objectUnderTest.extract(mockAdapter, apoParameterBean);
context.assertIsSatisfied();
}
The class I'm mocking:
public class ApoSAPExtractor implements SAPExtractor<ApoResults, ApoParameterBean> {
private final static Logger logger = Logger.getLogger(ApoSAPExtractor.class);
public List<ApoResults> extract(BapiAdapter b, ApoParameterBean pb) throws JCoException, Exception {
checkParm(b);
List<ApoResults>list = new ArrayList<ApoResults>();
try {
b.activate();
JCoTable itp = b.getImportTableParameter(APOConstants.BAPI_IM_PARMS);
itp.appendRow();
JCoTable t = itp.getTable(APOConstants.BAPI_DOC_TYPES);
Utils.appendParm(t, pb.getDocTypes());
b.execute();
TableAdapter ta = b.getExportTableAdapter(APOConstants.BAPI_EX_PO_APO);
for (int i = 0; i < ta.size(); i++) {
ApoResults ar = new ApoResults();
... lots of setters ...
list.add(ar);
ta.next();
}
} catch (Exception e) {
logger.info(String.format("Program %s failed.",this.getClass().getSimpleName(), "failed"));
e.printStackTrace();
throw e;
}
return list;
}
You can't inject things into a mock, you can set expectations on it
Instead of this (which gives you your unexpected exception):
mockAdapter.setName(BAPI_NAME);
you might do this in your expectations:
atLeast(1).of(mockAdapter).getName();
will(returnValue(BAPI_NAME));