0

I'm having an issue with a JUnit test I made. The method I'm testing takes an InputStream should throw an exception if the passed InputStream doesn't support mark/reset.

The problem I am running into is that my test to ensure an exception gets thrown when an InputStream that doesn't support mark/reset gets passed (posted below) keeps throwing an AccessDeniedException.

public class IOTest{

    @Rule
    public TemporaryFolder tempFolder = TemporaryFolder()

    @Before
    public void createFolder() throws IOException {
        Files.createDirectories(tempFolder.getRoot().toPath().resolve("testFile"));
    }

    @Test(expected = IllegalArgumentException.class)
    public void testDetectCharsetOnlyAcceptsMarkResetSupportedInputStreams() throws IOException {
        final Path testPath = tempFolder.getRoot().toPath().resolve("testFile");
        final InputStream testStream = Files.newInputStream(testPath);
        IO.detectCharset(testStream);
    }
}

I think the problem I'm running into has to do with accessing the temporary folder, but I don't know how to circumvent this.

Here is the stack trace that gets printed when I run this test:

java.lang.Exception: Unexpected exception, expected<java.lang.IllegalArgumentException> but was<java.nio.file.AccessDeniedException>
    at org.junit.internal.runners.statements.ExpectException.evaluate(ExpectException.java:28)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.rules.ExternalResource$1.evaluate(ExternalResource.java:48)
    at org.junit.rules.RunRules.evaluate(RunRules.java:20)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:252)
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:141)
    at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:112)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
    at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
    at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
    at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115)
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75)
Caused by: java.nio.file.AccessDeniedException: C:\Users\antho\AppData\Local\Temp\junit4390480127201295432\testFile
    at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:83)
    at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:97)
    at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:102)
    at sun.nio.fs.WindowsFileSystemProvider.newByteChannel(WindowsFileSystemProvider.java:230)
    at java.nio.file.Files.newByteChannel(Files.java:361)
    at java.nio.file.Files.newByteChannel(Files.java:407)
    at java.nio.file.spi.FileSystemProvider.newInputStream(FileSystemProvider.java:384)
    at java.nio.file.Files.newInputStream(Files.java:152)
    at com.bunnell.anthony.booker.IOTest.testDetectCharsetOnlyAcceptsMarkResetSupportedInputStreams(IOTest.java:65)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.ExpectException.evaluate(ExpectException.java:19)
    ... 24 more

I'm guessing it has something to do with permissions and the OS, but I'm just not sure how to get around this problem. If it helps, I'm using Windows 10.

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
AnthonyB
  • 3
  • 1
  • 4

2 Answers2

5

You're trying to read from testFile, which is not a file but a directory; you're creating with

Files.createDirectories(tempFolder.getRoot().toPath().resolve("testFile"));

whose documentation says:

Creates a directory by creating all nonexistent parent directories first.

(emphasis mine)

Community
  • 1
  • 1
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • `@Before public void createFolder() throws IOException { Files.createDirectories(tempFolder.getRoot().toPath()); }` – AnthonyB Jun 18 '16 at 08:21
  • `@Test(expected = IllegalArgumentException.class) public void testDetectCharsetOnlyAcceptsMarkResetSupportedInputStreams() throws IOException { Files.createFile(tempFolder.getRoot().toPath().resolve("testFile")); final Path testPath = tempFolder.getRoot().toPath().resolve("testFile"); final InputStream testStream = Files.newInputStream(testPath); IO.detectCharset(testStream); }` – AnthonyB Jun 18 '16 at 08:25
  • This test now passes by throwing the correct exception. Thanks for the help! – AnthonyB Jun 18 '16 at 08:28
0

In order to keep your JUnit tests portable and simple, I would suggest removing the external file dependency entirely.

You can do this in two ways:

  1. Create an InputStream from something internal, like a String or byte array. Here is how with strings

  2. Use a mocking framework, such as Mockito, to create a dummy InputStream that has just enough functionality to confirm that the method works. This would be my preferred strategy, as mocking produces much cleaner tests.

Community
  • 1
  • 1
Brandon McKenzie
  • 1,655
  • 11
  • 26
  • First, thank you for your suggestions. It looks like the top answer for creating an InputStream from a String uses a ByteArrayInputStream, (as would creating an InputStream from a byte array) which supports mark/reset. I need to create an InputStream that doesn't have this functionality for my test. I have used Mockito before. It is a very powerful and useful tool, without a doubt, but in this instance, I was attempting to stick with a TemporaryFile. However, I will look into what Mockito offers as far as dummy InputStreams for future use. – AnthonyB Jun 18 '16 at 08:14