Edit: I realized after writing this that your question specifically mentioned Mocha and my example code used QUnit. Sorry 'bout that.
Small point here. If you are instantiating a component to unit test a function/property on that component then I would argue that function/role is not a component concern and should instead be moved out of the component and into a utility file. The distinction is that unit tests help to verify the contract/API that an internal object exposes. Much like you would not test private functions of a class because that is implementation details you just want to know that if your class has a prescribed state that it behaves in an expected way.
Components, however, play a specific role in that they manage a section of the DOM. Looking at components from that role would mean your public interface/API is the DOM itself and therefor should be tested as integration tests leaving the nitty gritty as implementation details and test the interface using the messaging framework that is the integration tests.
I do this even for utility like components which don’t actually involve the DOM other then to provide data to other components I will also design the test as an integration test.
Ultimately my rule of thumb is if my public interface my subject under test is meant to be used by more JavaScript code then I will unit test it. If my public interface under test is meant to be used in a template then I will integration test it.
Another great rule of thumb I use is that if I unit test an object and cover its edge cases then I am free to mock its use elsewhere (most likely in an integration test). For example if I unit test my model then I now have permission to make fakes, mocks, even disparate duck types of that model for components that would normally take that model as an attribute. With this rule of thumb I also expand that to: if I integration my components so that they cover all the edge cases that component is responsible for then I have permission to make an acceptance test that is just the happy path knowing all the edge cases have been handled in integration tests.
For clarification, in my integration tests I will use the following pattern/practices:
Stub actions with spies
Either manual or Sinon.JS (if given the choice).
let callCount = 0;
this.set('actionSpy', () => callCount++);
await render(hbs`<MyComponent @myAction={{action this.actionSpy}} />`);
assert.equal(callCount, 1);
Mock data passed in
this.set('testData', 'foo');
await render(hbs`<MyComponent @data={{this.testData}} />`);
let result = find('#my-component [data-test=rendered-data]').textContent.trim();
assert.equal(result, 'foo');
run(() => this.set('testData', 'bar');
result = find('#my-component [data-test=rendered-data]').textContent.trim();
assert.equal(result, 'bar');
In the case of a model I might use a POJO or if the component needs the ember-data model API:
const MockModel = EmberObject.extend({
save() {}
});
// ...
this.set('testData', MockModel.create({
name: 'foobar'
}));
Provide outlets for derived state that are yielded
await render(hbs`
<MyComponent as |value|>
<span id="test-value">{{value}}</span>
</MyComponent>
`);
let result = find('#test-value').textContent.trim();
I also use buttons to click for any actions a component yields.
Use Page Objects for any inspection of the DOM inside the template
ember-cli-page-object is amazing for this!