5

I have a method:

public class MarginConverter {
    int top = 0;
    int bottom = 0;
    int right = 0;
    int left = 0; 
    public MarginConverter(String val){
       top = bottom = right = left = Integer.parseInt(val);
    }

    public LayoutParams getLayoutParamsFromView(View view){
        LayoutParams layoutParams = (LayoutParams) view.getLayoutParams();
        int height, width;
        if (layoutParams == null) {
            height = LayoutParams.WRAP_CONTENT;
            width = LayoutParams.MATCH_PARENT;
            layoutParams = new LayoutParams(width, height);
            layoutParams.setMargins(left, top, right, bottom);
        } else {
            layoutParams.setMargins(left, top, right, bottom);
        }
        return layoutParams;
        }
    }

Note: Variables left, top, right, bottom are instance variables initialized on constructor call.

I want to test this method. I have mocked view.getLayoutParams() method. Method setMargin(int, int, int,int) is not setting margin parameters as mentioned and I am getting all parameters of LayoutParams(leftMargin, rightMargin, topMargin, bottomMargin) 0.0 in test though it's working correctly in code. What should I do so that I will get values as expected.

Please help me ! Any help will be appreciated..

This is my testCase code:

@RunWith(PowerMockRunner.class)
@PrepareForTest({ViewGroup.LayoutParams.class})
public class MarginConverterTest {
@Mock
private View view = mock(TextView.class);

private int left = 0;
private int right = 0;
private int top = 0;
private int bottom = 0;

@Before
public void setUp() throws Exception {
    when(view.getLayoutParams()).thenReturn(null);
}

/**
 * tests output for margin conversion when one argument is given
 */
@Test
public void test_OneArgumentMarginConversion(){
    left =top = right = bottom = 5;
    MarginConverter marginConverter = new marginConverter("5");
    LayoutParams params = marginConverter.getLayoutParamsFromView(view);
    Object[] marginArray = new Object[4];
    marginArray[0] = params.leftMargin;
    marginArray[1] = params.topMargin;
    marginArray[2] = params.rightMargin;
    marginArray[3] = params.bottomMargin;
    Assert.assertArrayEquals(new Object[]{left,top,right,bottom}, marginArray);
}
}
Anuja Kothekar
  • 2,537
  • 2
  • 15
  • 28

2 Answers2

3

You seem to be confused about concept of mocking. If you mock something, it means its a dummy ( not real object ) and all of its method calls are fake.

If you wish margins to be non-zero , LayoutParams(leftMargin, rightMargin, topMargin, bottomMargin) , don't mock view or setMargin method.

If your view object is not real ( mocked , dummy etc ), your layoutParams is a fake one too ( means unknown values ) unless you are returning an actual layoutParams by using some mocking framework.

In simple terms, if you wish to set margins by calling setMargins , don't mock setMargins method call and make sure that layoutParams is not fake one.

Also, in your case if view is mocked, condition if (layoutParams == null) will never be satisfied as layoutParams will be a non - null fake object.

Solution - use an appropriate mocking method on call view.getLayoutParams() to return an appropriate real layoutParams object or null to satisfy both branches of code , if as well as else.

Hope it helps and let me know if I misunderstood your question.

Sabir Khan
  • 9,826
  • 7
  • 45
  • 98
  • I want to check whatever margins I apply should be in LayoutParams that are returned from function. Your solution helped me to test for both branches of code. But my question remains the same. What should I do so that I can set value of fields in layoutParams on call of setMargins method. – Anuja Kothekar May 09 '16 at 06:31
  • In your test method, you are calling `marginConverter.getLayoutParams(view)` while method that you wish to test is `getLayoutParamsFromView` and I don't see that method being called from your test. Am I missing something? You seem to be providing info in bits & pieces. – Sabir Khan May 09 '16 at 08:58
  • I assume your problem is the expectation to have instance variables `left, top,right, bottom` to be set as per your wish by doing `left =top = right = bottom = 5;` in test method? I guess you need to show constructor then otherwise how would anyone know about setting of these values? If these values are being set properly in constructor by call, ` MarginConverter marginConverter = new marginConverter("5");` then I don't see any reason for these to be 0 if you are going down path , `if (layoutParams == null)`. – Sabir Khan May 09 '16 at 09:11
  • Concept is simple, if `layoutParams` is not mocked, method call `layoutParams.setMargins(left, top, right, bottom);` is real and you need to verify these values before calling this method too. So are these values non - zero just before you call `setMargins` i.e. are these values initialized properly before you make the function call? – Sabir Khan May 09 '16 at 09:15
  • I have checked by debugging code, values are non-zero i.e. 5 in this case before making function call. I have edited post with whole class to test(MarginConverter) and whole test class testing MarginConverter – Anuja Kothekar May 09 '16 at 09:38
  • so your method works OK if called from a normal client i..e not Junit or PowerMock code? Can't see anything else other than suggesting to move line `when(view.getLayoutParams()).thenReturn(null);` from setUp to test method ( but that should not have any impact ). – Sabir Khan May 09 '16 at 10:19
  • Saw these questions on SO , [Q1](http://stackoverflow.com/questions/8175457/relative-layout-ignoring-setmargin) , [Q2](http://stackoverflow.com/questions/8209091/marginlayoutparams-setmargins-is-not-working) and might be related but you say that code is working Ok ( i.e. `setMargins` works OK ) in its own but I don't see anything suspicious in your test code. – Sabir Khan May 09 '16 at 10:19
  • That doesn't work for me but anyways thanks for your quick help and responses @Sabir Khan – Anuja Kothekar May 12 '16 at 03:35
0

As I was mocking view, view was not actually created which leads to this problem. I used RobolectricTestRunner instead of PowerMockRunner and created view using shaddow application context. And it worked..!

Now my testcode is:

@RunWith(RobolectricTestRunner.class)
public class MarginConverterTest {
private int left = 0;
private int right = 0;
private int top = 0;
private int bottom = 0;
View view;
@Before
public void setUp() throws Exception {
   view = new TextView(Robolectric.getShadowApplication().getApplicationContext());
}

/**
 * tests output for margin conversion when one argument is given
 */
    @Test
    public void test_OneArgumentMarginConversion(){
    left =top = right = bottom = 5;
    MarginConverter marginConverter = new marginConverter("5");
    LayoutParams params = marginConverter.getLayoutParamsFromView(view);
    Object[] marginArray = new Object[4];
    marginArray[0] = params.leftMargin;
    marginArray[1] = params.topMargin;
    marginArray[2] = params.rightMargin;
    marginArray[3] = params.bottomMargin;
    Assert.assertArrayEquals(new Object[]{left,top,right,bottom}, marginArray);
}
}
Anuja Kothekar
  • 2,537
  • 2
  • 15
  • 28