0

I have a class like this:

public class CloudFormationManager
{
    private static CloudFormationManager cloudFormationManager;
    private final AmazonCloudFormation amazonCloudFormation;

    private CloudFormationManager(final AmazonCloudFormation amazonCloudFormation)
    {
        this.amazonCloudFormation = amazonCloudFormation;
    }

    public List<StackResource> getStackResources(final String stackName)
    {
        ListStackResourcesRequest listStackResourcesRequest = new ListStackResourcesRequest();
        listStackResourcesRequest.setStackName(stackName);
        ListStackResourcesResult listStackResourcesResult =
                amazonCloudFormation.listStackResources(listStackResourcesRequest);

        if (nonNull(listStackResourcesResult))
            return getStackResources(listStackResourcesResult);
        else
            return Collections.emptyList();
    }
}

I am beginning to write UT's for this using Mockito which is as follows:

@Test
public class CloudFormationManagerTest
{
    @Mock
    private AmazonCloudFormation amazonCloudFormation;

    @InjectMocks
    CloudFormationManager cloudFormationManager;

    @BeforeMethod
    public void setUp() throws IOException
    {
        CloudFormationManager cloudFormationManager = new CloudFormationManager(amazonCloudFormation); // this statement gives an error.
        MockitoAnnotations.initMocks(this);
    }

    @Test
    void testGetStackResources()
    {

    }

}

Now, in the setUp() method, I see an error saying that this class cannot be initialised and I understand this since it's a private constructor? How do I initialise it then using Mockito?

sarah
  • 247
  • 1
  • 9
  • 19
  • You need `PowerMockito` instead, please have a quick google search. – Bk Santiago Jun 23 '17 at 03:48
  • 1
    How do you initialize it in app code? Don't you need a builder / factory method? Something like `CloudFormationManager.create(AmazonCloudFormation acf)` – Paul Hicks Jun 23 '17 at 03:54
  • You probably _don't_ need PowerMockito. However your actual application creates a `CloudFormationManager` would be something you need to replicate in your test. – Dawood ibn Kareem Jun 23 '17 at 03:57
  • @DawoodibnKareem, but I am writing the UT for that class itself. Will I have to inject CloudFormationManager in the class itself? – sarah Jun 23 '17 at 04:00
  • Also, with just a little bit of extra design work you could increase testablity and eliminate the need for mocking. Mocking is usually expensive (in development time), brittle, and not particularly valuable. – Paul Hicks Jun 23 '17 at 04:00
  • What I'm saying is - it must be possible to create a `CloudFormationManager`, because your application presumably does it. So however you've created it, do the same thing in the test. – Dawood ibn Kareem Jun 23 '17 at 04:01
  • Yep, sorry got it. It has been done like this, `CloudFormationManager.getInstance(amazonCloudFormation);`. Are you suggesting I should do a similar thing inside the setUp() method then? – sarah Jun 23 '17 at 04:05
  • 1
    Yes. And pass in your mock AmazonCloudFormation. – Dawood ibn Kareem Jun 23 '17 at 04:09

1 Answers1

0

It seems that you are not clear on what @Mock and @InjectMocks does.

Using @Mock, you create a mocked object. Using @InjectMocks, you have Mockito insert all @Mock objects into some object under test.

Your class CloudFormationManager has two fields. Thus you would probably need:

@Mock
private AmazonCloudFormation mockedAmazonCloud;

@Mock
CloudFormationManager mockedFormationManager;

@InjectMocks
CloudFormationManager cloudFormationManager;

and now Mockito should setup both fields upon calling initAnnotiations().

See here for further reading.

Ihor Patsian
  • 1,288
  • 2
  • 15
  • 25
GhostCat
  • 137,827
  • 25
  • 176
  • 248