1

I have a Bean that is reading a file at initialization. The file is environment specific and is generated during the installation of the system. The path of the file is hardcoded as a final static variable in the code.

private static final String FILE_PATH = "/etc/project/file.path";
private String decryptedPassword = "";

@Autowired
public ClassToBeTested(@Value("${pass}") String encryptedPassword)
{
    String decryptedPassword = StaticClass.decrypt(encryptedPassword, FILE_PATH);
}

I need to somehow mock this file in the JUnit tests so that I can test the rest of the functionalities. The @Before annotation is not useful because even that is run after initialization of the Beans according to my tests.

One very dirty way that can be used is to add another parameter to the Autowired function that can indicate if the call is for a unit test or not. But this is really not a clean way to do this. For example:

private static final String FILE_PATH = "/etc/project/file.path";
private String decryptedPassword = "";

@Autowired
public ClassToBeTested(@Value("${pass}") String encryptedPassword,
        @Value("${isTest}") boolean isTest)
{
    if (isTest)
        decryptedPassword = encryptedPassword;
    else
        decryptedPassword = StaticClass.decrypt(encryptedPassword, FILE_PATH);
}

Any ideas how I can mock the file at FILE_PATH so that I do not have to use this workaround or force a property in the Autowired function without changing the Bean constructor?

iSpardz
  • 451
  • 4
  • 6
  • Refactor the class to inject a `PasswordSupplier` or such into it. – chrylis -cautiouslyoptimistic- Jul 25 '16 at 16:55
  • I tried an approach to create a class to handle the decryption and to mock that in the setup for the tests. This approach works if the password decryption is not in the constructor of the bean. However, in my case, it has to be in the constructor because of legacy code issues. – iSpardz Jul 25 '16 at 17:04
  • 1
    Then you're screwed, since the constructor will throw if it can't get the file. Refactor if at all possible. Maybe you can add a saner constructor? – chrylis -cautiouslyoptimistic- Jul 25 '16 at 18:32

2 Answers2

3

You can use a tool like Whitebox to swap the FILE_PATH in your test context.

public class MyClass {
   private static  String MY_STRING = "hello";

   public void whatsMyString() {
       System.out.println(MY_STRING);
   }
}

Note that MY_STRING is not final

@Test
    public void testWhiteboxSwap() {
        MyClass test = new MyClass();
        test.whatsMyString();

        String testContextString = "\tgoodbye";
        Whitebox.setInternalState(MyClass.class, testContextString);
        test.whatsMyString();
    }

Console output:

hello
    goodbye

You may still need to play with the @Before or @BeforeClass in your test structure to get the timing right, but Whitebox can facilitate the behavior you're looking for.

Be aware that this is not a threadsafe solution. If multiple tests change the static reference the last one will win!

I use a maven project for my sample. I've attached the pom addition below.

<dependency>
    <groupId>org.powermock.tests</groupId>
    <artifactId>powermock-tests-utils</artifactId>
    <version>1.5.4</version>
</dependency>
Jeremiah
  • 1,145
  • 6
  • 8
0

In my specific case, the only way that I found was to refactor the code.

iSpardz
  • 451
  • 4
  • 6