ResourceResolverUse the resource resolver to get a parent resource then create a child in it
final Resource parentResource = resourceResolver.getResource(parentPath);
resourceResolver.create(parentResource, title, new HashMap<>());
This creates a node of sling:folder type.
This is fairly easy to unit test because the resourceResolver could be mocked either directly or using the SlingContext (https://sling.apache.org/documentation/development/sling-mock.html)
NodeYou can simply add one node from another node.
final Resource parentPathResource = resourceResolver.getResource(parentPath);
final Node parentJcrNode = parentPathResource .adaptTo(Node.class);
final Node newNode = parentJcrNode.addNode(title, "nt:unstructured");
This is probably the most straight forward way to create a node of a particular primary type. Here the type created is a nt:unstructured.
PageManagerThe PageManager can be used to create actual pages in the jcr similar to below
final Page page = pageManager.create(parentPath, childName, "", childName);
This creates a type of cq:Page. This is also easy to mock and test. Using this form also creates a jcr:content child node off the page which is useful in most instances.
The JcrUtil gives some great ways to manipulate the nodes. You can createPath() like here or createUniqueNode(),
However, the session object is needed and this is harder to unit test because the implementation is hidden.
jcr:contentCreating and setting properties on the jcr:content node is a simple case of getting the child from the resource object.
final Resource childResource = parentResource.getChild(JcrConstants.JCR_CONTENT);
final Node childNode = childResource .adaptTo(Node.class);
childNode.setProperty("jcr:description", "Description of the node");