Developer Test (DT) Case Writing Guide
1. Background
Unit testing (UT) and integration testing (ST) for openUBMC are implemented alongside the service code from the early stages of project planning. Their primary purpose is to ensure the functional correctness and efficient development of the service code and the reliability of external resources.
2. Development Process (Using the IAM Module as an Example)
- Build the overall service function framework.
- Develop the underlying data operation logic (UT).
- Summarize service layer operations (UT).
- Manage resource tree data (ST).
- Test overall service functions (UT and ST).
3. UT Data Preparation and Cleanup
Principle: Tests must not depend on external environments (including default configurations and absolute paths).
Suggestions:
- Create a temporary directory and copy external dependency files into it.
- Set unified parameter entry points for configurations that require external input and configure them in configuration files.
- Data cleanup can be performed once in advance.
4. UT Mocking
Functions that depend on skynet or other modules can be implemented using temporary stubs.
Example: mocking KMC functions
Two mocking methods are available for reference:
local kmc = require 'mc.kmc'
local KmcEnc = kmc.encrypt_data
local KmcDec = kmc.decrypt_data
function TestIam:setUp()
-- mock kmc
kmc.encrypt_data = function(domain_id, cipher_alg_id, hmac_alg_id, plaintext)
return plaintext
end
kmc.decrypt_data = function(domain_id, ciphertext)
return ciphertext
end
end
function TestIam:tearDown()
kmc.encrypt_data = KmcEnc
kmc.decrypt_data = KmcDec
end-- Implement a kmc_client yourself: hica/apps/security/src/lualib/certificate/infrastructure/kmc_client.lua
function TestCertificate:setupClass()
-- Other operations
self.kmc_client = KmcClient.new(nil, true)
-- mock KMC
self.kmc_client.decrypt_cert_key = function(cls, encrypt_string)
return encrypt_string
end
self.kmc_client.encrypt_cert_key = function(cls, plaintext)
return plaintext
end
end5. UT Debugging
Test-driven development is a powerful tool for improving efficiency. You can debug directly by pressing F5, which is essential for developing service functions in an x86 environment.
6. ST Resource Tree and RPC Requests
Many functions need to be added to the resource tree. Since UT cannot interact with D-Bus, functions involving the resource tree must be tested in ST.
Related RPC operations:
local function get_property(bus, prop_name)
return bus:call('ibmc.app.Iam', '/bmc/kepler/SessionService',
'org.freedesktop.DBus.Properties', 'Get', 'ss', 'bmc.mdb.SessionService', prop_name):value()
end
local function set_property(bus, prop_name, value)
return bus:call('ibmc.app.Iam', '/bmc/kepler/SessionService',
'org.freedesktop.DBus.Properties', 'Set', 'ssv', 'bmc.mdb.SessionService', prop_name, gvariant.new_uint32(value))
endSince ST starts relevant services, underlying functions do not need to be mocked and can be used directly, facilitating joint debugging and testing of overall functions.
function AccountCases.test_change_account_pwd(bus)
assert(iam:ChangeAccountPwd(bus, 2, "Administrator", "xxx") ~= nil)
local ret = iam:Authenticate(bus, "Administrator", "xxx")
assert(ret.UserId == 2)
assert(iam:ChangeAccountPwd(bus, 2, "Administrator", "xxx") ~= nil)
end7. ST Debugging
Adding print logs from the top-level module to the bottom-level module allows for flexible testing and debugging.
Note:
skynetsupports the console. Currently,skynetservice debugging can be implemented using VS Code plugins or other methods. For details, see https://github.com/colinsusie/skynetda.
8. Case Coupling and Decoupling
- Service logic cohesion: Maintain the cohesion of service logic.
- Avoid overly complex operations in a single case: It is recommended that a single case calls 5 to 10 methods.