// 
//     Licensed to the Apache Software Foundation (ASF) under one
//     or more contributor license agreements.  See the NOTICE file
//     distributed with this work for additional information
//     regarding copyright ownership.  The ASF licenses this file
//     to you under the Apache License, Version 2.0 (the
//     "License"); you may not use this file except in compliance
//     with the License.  You may obtain a copy of the License at
// 
//       http://www.apache.org/licenses/LICENSE-2.0
// 
//     Unless required by applicable law or agreed to in writing,
//     software distributed under the License is distributed on an
//     "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
//     KIND, either express or implied.  See the License for the
//     specific language governing permissions and limitations
//     under the License.
//

= TestingThingsThatUseFileObjectDataObjectDataFolder
:jbake-type: wiki
:jbake-tags: wiki, devfaq, needsreview
:jbake-status: published
:keywords: Apache NetBeans wiki TestingThingsThatUseFileObjectDataObjectDataFolder
:description: Apache NetBeans wiki TestingThingsThatUseFileObjectDataObjectDataFolder
:toc: left
:toc-title:
:syntax: true

== Testing Things That Use FileObject/DataObject/DataFolder

If your unit tests use `FileObject` (including `DataObject` or `DataFolder`), then you may be suprised that `FileUtil.toFileObject(java.util.File)` returns `null`. This is because the MasterFS filesystem implementation is what maps `FileObject`s to your local disk and it needs to be on the classpath when tests are run.

See link:UsingFileSystemsMasterfs.asciidoc[UsingFileSystemsMasterfs] for more info on how to fix this.

If for some reason you prefer not to use MasterFS, you can create a new `LocalFileSystem`, create some files and use that instead of `FileUtil.toFileObject` in your test.  For example, in a `NbTestCase` subclass:

[source,java]
----

FileObject dir;
public @Override void setUp() throws Exception {
  super.setUp();
  clearWorkDir();
  LocalFileSystem fs = new LocalFileSystem();
  fs.setRootDirectory(getWorkDir());
  dir = fs.getRoot();
}
----

If your test just needs some simple data in a FileObject or two, you can avoid writing to disk at all as follows:

[source,java]
----

FileObject dir;
public @Override void setUp() throws Exception {
  super.setUp();
  dir = FileUtil.createMemoryFileSystem().getRoot();
  //write out data your tests will use to files under dir/ here
}
----

If you want to write tests for a `DataObject` or `DataLoader`, you may also want to set the mime type correctly: link:DevFaqTestDataObject.asciidoc[DevFaqTestDataObject]

== Apache Migration Information

The content in this page was kindly donated by Oracle Corp. to the
Apache Software Foundation.

This page was exported from link:http://wiki.netbeans.org/TestingThingsThatUseFileObjectDataObjectDataFolder[http://wiki.netbeans.org/TestingThingsThatUseFileObjectDataObjectDataFolder] , 
that was last modified by NetBeans user Geertjan 
on 2011-05-13T13:08:00Z.


*NOTE:* This document was automatically converted to the AsciiDoc format on 2018-02-07, and needs to be reviewed.
