0

How to mock the object for the Phone object.

code bellow,

public class Fortest {

  UserDao userdao = new UserDao();
  Phone name = new Phone();
  public String handleUser(User user) {

    String returncode="failed";
    //User usr = new User("bob");
    String username=user.getUsername();
    String pass=user.getPass();
    System.out.println("username and password : "+username+" : "+pass);

    Phone name = new Phone();
    String ph = name.getA();
    System.out.println("ph "+ph);

    if(ph.equalsIgnoreCase("test")){
      System.out.println("A "+ph);
      returncode="done";
    }
    System.out.println("returning "+returncode);

    return  returncode;
    //System.out.println("name "+name.toString());
    //System.out.println(name.getA());
  }
}

Thanks

Simulant
  • 19,190
  • 8
  • 63
  • 98
Jyosna
  • 4,436
  • 13
  • 60
  • 93
  • Question, since you have a `name` field, do you also need a `name` created in the method? Testing changes greatly depending on the answer. – John B Sep 05 '12 at 11:19
  • possible duplicate of [code to call the object of another class in a method](http://stackoverflow.com/questions/12279614/code-to-call-the-object-of-another-class-in-a-method) – John B Sep 05 '12 at 11:21
  • Is this some kind of homework question? If yes, tag it as homework. – Sylar Sep 05 '12 at 12:05

4 Answers4

2

You don't. One of the rules of mocking is: you never mock entities or value objects. If you need to break this rule, it means that you probably have a design flaw.

If you need to mock a new, you'll need to pass a factory to the object, and then you mock the factory. A very common example of this is when you need to mock Date objects, which is very well explained in this other question: How to mock the default constructor of the Date class (check the first answer).

As a side note, calling an instance of Phone name...mmm that doesn't look right.

Community
  • 1
  • 1
Augusto
  • 28,839
  • 5
  • 58
  • 88
  • I am not sure `Phone` is a value type since it has a default constructor and then seems to get a non-constant for `getA`. – John B Sep 05 '12 at 11:20
  • Hi John, I agree, it's not a value object. It looks more like an entity (I'm using the DDD naming). – Augusto Sep 05 '12 at 15:18
  • I agree the name sounds like a value object. What is DDD? – John B Sep 05 '12 at 16:19
  • John, DDD stands for [Domain Driven Design](http://en.wikipedia.org/wiki/Domain-driven_design). I **strongly** suggest to read about it if you want to build medium to large applications. – Augusto Sep 05 '12 at 19:13
2

First I'm going to make some assumptions. user.getUsername() & user.getPass() have no side affects. The System.out.println are not important to you.

Thus done your class becomes:

public class Fortest {
    Phone name = new Phone();

    public String handleUser(User user) {
        String ph = name.getA();

        if(ph.equalsIgnoreCase("test")){
            return "done";
        }

        return  "failed";

    } 
}

So your test has two conditions. Either phone.getA() is "test" and you return "done" or it is not and you return "failed".

So how to set set "getA". One thing is for sure, we will need to be able set "name" from the test. For that we need to "inject" it (we can do it a number of other ways, but I loves injection). I'd use Guice, many would use Spring. Some would use one of the other injection frameworks. But in the tests most of us would use manual injection.

public class Fortest {
    Phone name;
    Fortest(Phone name) {
        this.name = name;
    }

    public String handleUser(User user) {
        String ph = name.getA();

        if(ph.equalsIgnoreCase("test")){
            return "done";
        }

        return  "failed";

    } 
}


public class TestFortest {
   @Before
   public void before() {
          name = ; //... 
          subject = new Fortest(name);
   }
}

Now the tests are fairly simply:

public void whenTestModeIsEnabledThenReturnDone() {
     setPhoneIntoTestMode();
     String actual = subject.handleUser(null);
     assertEquals(actual, "done");
}

public void whenTestModeIsDisabledThenReturnFailed() {
     setPhoneIntoLiveMode();
     String actual = subject.handleUser(null);
     assertEquals(actual, "failed");
}

The implementation of setPhoneIntoTestMode/setPhoneIntoLiveMode will depend on how complex Phone is. If it is complex than we would look at "facking" it in some way (mocks, stubs, etc). This could be a chunk of code you write, it could be using a tool like Mocketo.

If the Phone object is simple, and has or can have a "setA" method, then just use that.

I'm sure later you will need userdao. The same thing will be done at that point. Inject and mock/setup the object.

Michael Lloyd Lee mlk
  • 14,561
  • 3
  • 44
  • 81
0

Class mocking is very easy using EasyMock. It makes use of cglib internally to perform class mocking. EasyMock can both mock interfaces and classes (class mocking). See documentation.

So, to get your Phone mock, just call createMock(Phone.class):

Phone phoneMock = createMock(Phone.class);

As Augusto stated, it is not really good design to make use of class mocking though. A better way would be to program towards interfaces and use a dependency injection framework.

Sylar
  • 2,273
  • 2
  • 18
  • 26
0

So you need to do one of the following options to inject mocks into the fields name and userdao (I am going to assume that you can use the new Phone field instance instead of the one created in the method.

  1. Do not call constructors in your code directly but instead use field injection via setters. This will allow your test to provided mocked instances of the two classes. If you must create a new instance in the method then consider using a factory which can be mocked.

  2. Provide default scope setter methods for the two fields. These methods would be in place for test purposes only.

  3. Use Refection to set the fields to mocked instances. An easy way to do this is with Spring's ReflectionTestUtils.

Once one of these is in place you can provide mocked instances (maybe using Mockito) to drive the behavior you wish to test. I would suggest that option 1 is the best if fesible, then option 3. However, the disadvantage to options 3 is that the test is dependant of the names of private fields.

Then...

Phone phone = Mockito.mock(Phone.class);
Mockito.when(phone.getA()).thenReturn("blah");
objectUnderTest.setPhone(phone);

objectUnderTest.handleUser(...);
John B
  • 32,493
  • 6
  • 77
  • 98