0

I am having a problem setting up this method under test in junit. I am trying to test the method to updateConfigDates with a new timestamp. Please bear with me here, as there is a lot of information provided and it doesn't really look too pretty.

Here is the method under test.

public static Document updateConfigDates(Document doc, Timestamp configDate)
{
    //Format timestamp to string
    String configTimestampStr = GTR_DATE_FORMAT.format(configDate) + "Z";

    //Change configuration date for all nodes in GTR
    NodeList configIDNodes = doc.getElementsByTagName("ConfigDate");
    for (Element cidNode : new DOMUtil.ElementList(configIDNodes))
    {
        cidNode.setTextContent(configTimestampStr);
    }

    return doc;
}

The problem is on the line:

    //Format timestamp to string
    String configTimestampStr = GTR_DATE_FORMAT.format(configDate) + "Z";

Which is using a public final class Constants

public final class Constants
{
    /** GTR Timestamp formatter without micro-second */
    public static final FastDateFormat GTR_DATE_FORMAT 
                           = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss");
}

Here is my current test case

@Test
public void testUpdateConfigDates() throws Exception
{
    // check if configDate in document is expected
    String docConfigDate = doc.getElementsByTagName("ConfigDate").item(0).getTextContent();
    assertEquals(docConfigDate, "2012-02-22T16:07:27Z");

    LOG.info("docConfigDate: " + docConfigDate);

    // variables
    Timestamp newConfigDate = Timestamp.valueOf("2009-07-29 13:24:11");

    // Mocking statics
    //PowerMockito.mockStatic(GTRConstants.class);

    // String configTimestampStr = GTR_DATE_FORMAT.format(configDate) + "Z";
    //common.setFinalStatic(GTRUtility.class.getDeclaredField("configTimestampStr"), "yyyy-MM-dd'T'HH:mm:ss" + "Z");
    common.setFinalStatic(Constants.class.getDeclaredField("GTR_DATE_FORMAT"), FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss"));

    /* setFinalStatic ExceptionInInitializerError information below
     * 
     * Field#set(Object, Object) can be used to set static fields.
     * If you try to set the field of an uninitialized class, the JVM will first try to initialize the class.
     * If a failure occurs, then set will throw a ExceptionInInitializerError.
     */

    // execute method under test
    doc = gtrUtility.updateConfigDates(doc, newConfigDate);

    // verify expectations
    docConfigDate = doc.getElementsByTagName("ConfigDate").item(0).getTextContent();
    assertEquals(docConfigDate, "2009-07-29 13:24:11");
}

Using a setFinalStatic solution posted here, which successfully works with some other tests I'm doing.

public static void setFinalStatic(Field field, Object newValue) throws Exception
{
    field.setAccessible(true);
    // remove final modifier from field
    Field modifiersField = Field.class.getDeclaredField("modifiers");
    modifiersField.setAccessible(true);
    modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
    field.set(null, newValue);
}

I have tried several solutions:

  • My new and most recent method, using setFinalStatic method
  • Mocking Constants result with PowerMockito and Mockito.
  • Mocking GTR_DATE_FORMAT instance with PowerMockito and Mockito.
  • Mocking FastDateFormat with PowerMockito and Mockito.

All of which have failed. I think the setFinalStatic method is the closest, however I am currently getting error ExceptionInInitializerError (as also discussed from a user here and in Oracle Doc here)

weteamsteve
  • 189
  • 3
  • 20
  • 1
    Why do you want to mock GTR_DATE_FORMAT? Why not just supply a formattable value and let the formatting eb _part_ of your test. It feels like trying to exlcude the actual formatter from your test flow is a step too far. Alternatively, if you really ust exclude the formatter from your test flow then you could hide it behind an interface and make a mocked instance of that interface available to `updateConfigDates()` when that method is invoked by your test case. – glytching Feb 13 '18 at 16:06
  • You could probably use Power mock to get achieve what you are trying to do – ps. Feb 13 '18 at 16:15
  • Initially, I kept on getting an error on that line, even when supplying a formattable value. So I wanted to mock that and I figured that would keep the scope more within my class under test. – weteamsteve Feb 13 '18 at 16:16
  • Alternatively, you could modify the method to accept a `FastDateFormat` parameter. – Code-Apprentice Feb 13 '18 at 16:16
  • I have been using PowerMockito. I've tried mocking the result and object instances, and neither worked. – weteamsteve Feb 13 '18 at 16:16
  • I can't modify the class under test – weteamsteve Feb 13 '18 at 16:16
  • What error were you getting originally? It sounds like you should ask a question about that issue instead of your proposed solution. – Code-Apprentice Feb 13 '18 at 16:17
  • If I pass in a date that is the correct format, I get ExceptionInInitializerError. I have a method to test setId, which sets an integer and it works. And I am testing this method to set a date, with a timestamp of a certain format, and it won't work. No matter how I try to approach it. And it is because of the funkiness of line: `String configTimestampStr = GTR_DATE_FORMAT.format(configDate) + "Z";` and `public static final FastDateFormat GTR_DATE_FORMAT = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss");` – weteamsteve Feb 13 '18 at 16:30

1 Answers1

0

It turns out the answer to my problem was that the Constants file was executing some initialization methods (in this case: safeGetTypeId(x) on an object, from database) that I have to mock.

I should have noticed this faster when realizing that updateObjectId hardcoded test was working and the updateTimestamp using the constants class GTR_DATE_FORMAT.

The constructors were empty and I wasn't expecting anything else to be executed.

This is kind of an extreme and complicated question, so I may delete this question, however if it could help somebody in the future I will leave it.

weteamsteve
  • 189
  • 3
  • 20