How to mock ubus calls¶
Declare ubus: null in your utest.config.uc mocks table before using any of the patterns below. See How-to: Mock a module with mock.inject() for the setup steps.
Seed data with the object:method key format¶
Each key in the data map uses 'object:method' format. The value is returned as the result of conn.call(object, method, args):
import { describe, it, mock, assert, truthy, falsy } from 'utest';
describe('ubus mock', () => {
it('returns mocked data for object:method key', () => {
mock.inject('ubus', {
data: { 'system:board': { model: 'Test Router', hostname: 'OpenWrt' } }
}, (m_ubus) => {
let conn = m_ubus.connect();
assert.match({ model: 'Test Router', hostname: 'OpenWrt' }, conn.call('system', 'board', {}));
});
});
});
Object-only fallback¶
Use a bare object name (without :method) as a catch-all for any method on that object. The object-only key is tried when no object:method key matches:
mock.inject('ubus', {
data: { 'network': { up: true } }
}, (m_ubus) => {
let conn = m_ubus.connect();
assert.match(truthy(), conn.call('network', 'status', {}).up);
assert.match(truthy(), conn.call('network', 'get_status', {}).up);
});
Static vs function values for dynamic responses¶
Set the value to a plain object for a static response, or to a function for a dynamic one. The function receives the args passed to call() and must return the response:
mock.inject('ubus', {
data: { 'network:status': (args) => ({ up: args.interface == 'wan' }) }
}, (m_ubus) => {
let conn = m_ubus.connect();
assert.match(truthy(), conn.call('network', 'status', { interface: 'wan' }).up);
assert.match(falsy(), conn.call('network', 'status', { interface: 'lan' }).up);
});
Unmocked calls in non-strict mode¶
In non-strict mode, calling an unmocked object/method returns null:
mock.inject('ubus', { data: {} }, (m_ubus) => {
assert.match(null, m_ubus.connect().call('unmocked', 'method', {}));
});
Exercise code paths that call disconnect()¶
disconnect() is a no-op by default. If you need to verify that the code under test disconnects correctly, inspect the connection's call log with spy() (call it on the connection object returned by connect()):
import { spy } from 'utest';
mock.inject('ubus', { data: { 'system:board': { hostname: 'OpenWrt' } } }, (m_ubus) => {
let conn = m_ubus.connect();
conn.call('system', 'board', {});
conn.disconnect();
assert.match(1, length(spy(conn).calls.disconnect));
});
To override disconnect behaviour entirely, supply a behavior.disconnect function.
Override call behavior entirely¶
Supply a behavior.call function to intercept all call() invocations regardless of their arguments:
mock.inject('ubus', {
behavior: { call: (obj, method, args) => ({ routed: obj + '.' + method }) }
}, (m_ubus) => {
assert.match('system.board', m_ubus.connect().call('system', 'board', {}).routed);
});
Next steps¶
- Fail loudly on unmocked calls: How-to: Use strict mode
- Intercept calls through the imported
ubusbinding: How-to: Patch global state with mock.global.patch() - Mock UCI configuration: How-to: Mock UCI