开发者

How to write a UT to mock an internal object in one method?

开发者 https://www.devze.com 2023-04-05 19:43 出处:网络
For example , I have a java class as below. I am going to开发者_如何转开发 write a unit test for doWork(), so I would like to control obj\'s behavior. But it is obvious that obj is instantiated intern

For example , I have a java class as below. I am going to开发者_如何转开发 write a unit test for doWork(), so I would like to control obj's behavior. But it is obvious that obj is instantiated internally.

How can I write this UT? Now I am using Junit+Mockito.

class ToBeTest{
    public ToBeTest(){}
    public boolean doWork(){
        OtherObject obj=new OtherObject();
        return obj.work();
    }
}

Thanks in advance. :)

BTW, The reality is I am writing UT for other person's class. So I don't want to change it. It has been fully tested by integration test.


If you can't change the code, you can use Powermock along with junit and Mockito to mock the construction of new objects.

@Test
public void testDoWork() throws Exception{

    MyTest mytest = new MyTest();

    OtherObj obj = new OtherObj();
    obj.test="mocked Test"; //here you can add any other needed values to obj

    PowerMockito.whenNew(OtherObj.class).withNoArguments().thenReturn(obj);

    String result = mytest.doWork();
    Assert.assertTrue(result.equalsIgnoreCase("mocked Test"));
}


The best way is to write code to support testing (Test-Driven Development is emphasizing this). At the moment, your code is written in the way which makes it difficult to test.

Please consider using dependency injection, because it helps you mock the dependent object.


This is a classical example where you should use dependency injection.

In short, instead of creating the object (dependency) internally, you pass it in the constructor or use a factory to create what you want (the factory returns the real implementation in production code and another in test). This gives you the possibility to change the implementation when you test.

Look at the examples following the like I provided or google for "Java dependency injection example".


You can't easily. I can think of two ways you can do this and neither are supported out of the box by Mockito or jUnit as far as I'm aware:

1) Byte code manipulation using cglib or similar library which would be moderately difficult to do and likely pretty fragile.

2) Alternate classloader. You can build a classloader that looks for an attempt to load the OtherObject class and replaces it with an anonymous OtherObject class that gives you the mocking behavior that you are looking for.

Most of the time you should be treating it as a dependency though. If you want to test opening a file, you probably actually want to test with a file so using the concrete class is probably fine. If you want to test a method's behavior that has opening a file as a part of it's logic, you could easily move that out to a dependency and then mock it out. In fact, that usually makes sense because what you store in a file one day, may need to be stored in a database another or be pulled down from the cloud on a third day, so segregating the logic around what you do with the file from the actual process of opening a retrieving the contents is often a logical separation of concerns anyway.


It's very easy:

import org.junit.*;
import mockit.*;

@Test
public void justMockIt()
{
    new NonStrictExpectations() { OtherObject o; { o.work(); result = true; }};

    assert new ToBeTest().doWork();
}

... when using JMockit.


You have written your code, and now you want to unit test it. This is the fundamental cause of your difficulty. I suggest a different approach.

  1. Express what the doWork() method is meant to do in terms of behaviour that can be observed only through public and protected (getter) methods of the ToBeTest class, or the public and protected methods of any objectys associated-with ToBeTest objects. Take a look at the Javadoc provided with the Java library: that describes what all those classes do without stating the bodies of the methods. When does yor method return true? When does it return false? What side effects does it have? You might find you need to add some getter methods to do this. You could express these in the Javadoc for your own code.
  2. Use the required behaviour to decide what kinds of assertions you can place in your unit-tests.
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号