Search code examples
javajunitautocloseable

Java Autocloseable Test


public class CloseableResource implements AutoCloseable {
private static boolean _closed = false;
int _n;

  public CloseableResource(int n){
    }
    
    public void use() throws Exception{
        throw new Exception("Exception");
    }
    
    @Override
    public void close() throws Exception{
        _closed = true;
    }
    
    public static boolean isClosed() {
        System.out.println(_closed);
        return _closed;
    }

@Test
public void testAutoClose() {
   boolean failed = false;

   try (CloseableResource res = new CloseableResource(2)) {
      assertTrue(res != null);
      res.use();
   } catch (Exception e) {
      assertTrue(CloseableResource.isClosed());
      failed = true;
   }
   assertTrue(failed == true);

   failed = false;

   try (CloseableResource res = new CloseableResource(3)) {
      assertTrue(res != null);
      res.use();
   } catch (Exception e) {
      fail("this code should not be reached");
      failed = true;
   } finally {
      assertTrue(CloseableResource.isClosed());
   }
   assertTrue(failed == false);
}

I am trying to make that test work, the close method seems to work but I can't figure out why the test doesn't, it always ends up with fail("this code should not be reached"). I need some guidance please.


Solution

  • private static boolean _closed = false; why is this static? Making it static sets it to true or false on all instances instead of on a specific instance. I am not sure this is the desired behavior. When you create a new CloseableResource new resources will remain closed. In the constructor, you MUST set the static _close back to false. This will make your test pass, but it will make for a lousy implementation.

    This is what I did to make it "work" with Java 8. With Java 8, there is no way that I know of to really test the auto-closeable attribute of your resource.

    public class CloseableResource implements AutoCloseable {
        private boolean _closed = false;
        int _n;
        
        public CloseableResource() {
            _n = 1;
        }
    
    //  public CloseableResource(int n) {
    //      _n = n;
    //  }
    
        public void use() throws Exception {
            if (_closed) {
                throw new Exception("Attempting to use a closed resource");
            }
        }
    
        @Override
        public void close() throws Exception {
            if(_closed) {
                throw new Exception ("Attempting to close a closed resource");
            }
            _closed = true;
        }
    
        public boolean isClosed() {
            System.out.println(_closed);
            return _closed;
        }
    
        @Test
        public void testAutoClose() {
    
            CloseableResource res = new CloseableResource();
            try {
                assertTrue(res != null);
                res.use();
                res.close();
            } catch (Exception e) {
                fail("This code should not be reached");
            }
    
            try {
                assertTrue(res != null);
                res.use();
            } catch (Exception e) {
                assertTrue(e.getMessage().equals("Attempting to use a closed resource"));
            }
            
            try {
                res.close();
            } catch (Exception e) {
                assertTrue(e.getMessage().equals("Attempting to close a closed resource"));
            }
        }
    }
    

    However, if using Java 9 or greater, you can declare the resource outside the try (it will be effectively final); thus allowing you to test the auto-closeable attribute of your resource effectively.

    @Test
    public void testAutoClose() {
        CloseableResource res = new CloseableResource();
        try(res) {
            assertTrue(res != null);
            res.use();
        } catch (Exception e) {
            fail("This code should not be reached");
        }
        
        try {
            res.use();
        } catch (Exception e) {
            assertTrue(e.getMessage().equals("Attempting to use a closed resource"));
        }
            
        try {
            res.close();
        } catch (Exception e) {
            assertTrue(e.getMessage().equals("Attempting to close a closed resource"));
        }
    }
    

    This will allow you to use the same object to test all conditions in the same test.