-
Notifications
You must be signed in to change notification settings - Fork 100
Testing mid level API
⚠️ Alpha API —tik4net.testingis in early development. The builder methods and class names may change in future releases.
Package:
tik4net.testing(NuGet) — add it to your test project only.
See also: Testing low-level API · Testing high-level API
TikFakeConnection intercepts at CallCommandSync. ITikCommand.Execute* methods call that
internally, so they work exactly as with a real connection — the real parsing logic (scalar
extraction, single-row enforcement, trap-to-exception conversion) runs unchanged.
using tik4net;
using tik4net.Testing;Building entities with private fields: when you need to set read-only entity properties (
.id,dynamic, …) useWithId/WithValuefromTikFakeEntityExtensions— see Testing high-level API — Building fake entity instances.
Commands that return only !done (e.g. /log/info, /system/reboot):
var conn = new TikFakeConnection()
.WithNonQuery(rows => rows.First().StartsWith("/log/"));
ITikCommand cmd = conn.CreateCommand("/log/info",
conn.CreateParameter("message", "test message"));
cmd.ExecuteNonQuery(); // succeedsCommands that return a single value — either =ret= in !done (e.g. /add) or a single
field in a single !re row (e.g. /system/identity/print):
// /add → returns new id via =ret= in !done
var conn = new TikFakeConnection()
.WithScalarResponse(
predicate: rows => rows.First() == "/ip/firewall/address-list/add",
value: "*42");
ITikCommand cmd = conn.CreateCommandAndParameters(
"/ip/firewall/address-list/add",
"list", "MY_LIST",
"address", "10.0.0.1");
string newId = cmd.ExecuteScalar();
Assert.AreEqual("*42", newId);// /system/identity/print → single-field !re row
var conn = new TikFakeConnection()
.WithResponse(
rows => rows.First() == "/system/identity/print",
new ITikSentence[]
{
new TikFakeReSentence(new Dictionary<string, string> { { "name", "MyRouter" } }),
new TikFakeDoneSentence(),
});
string identity = conn.CreateCommand("/system/identity/print").ExecuteScalar();
Assert.AreEqual("MyRouter", identity);Dynamic scalar — response depends on what was sent:
var conn = new TikFakeConnection()
.WithScalarResponse(
predicate: rows => rows.First() == "/ip/address/add",
valueFactory: rows =>
{
// derive fake id from the address parameter
string addr = rows.FirstOrDefault(r => r.StartsWith("=address=")) ?? "=address=unknown";
return addr.GetHashCode() > 0 ? "*10" : "*11";
});Commands that return multiple !re rows:
var conn = new TikFakeConnection()
.WithResponse(
rows => rows.First() == "/ip/route/print",
new ITikSentence[]
{
new TikFakeReSentence(new Dictionary<string, string>
{ { ".id", "*1" }, { "dst-address", "0.0.0.0/0" }, { "gateway", "192.168.1.1" } }),
new TikFakeReSentence(new Dictionary<string, string>
{ { ".id", "*2" }, { "dst-address", "10.0.0.0/8" }, { "gateway", "10.0.0.1" } }),
new TikFakeDoneSentence(),
});
ITikCommand cmd = conn.CreateCommand("/ip/route/print");
IEnumerable<ITikReSentence> routes = cmd.ExecuteList();
Assert.AreEqual(2, routes.Count());
Assert.AreEqual("0.0.0.0/0", routes.First().GetResponseField("dst-address"));var conn = new TikFakeConnection()
.WithResponse(
rows => rows.First() == "/system/resource/print",
new ITikSentence[]
{
new TikFakeReSentence(new Dictionary<string, string>
{
{ "cpu-load", "12" },
{ "free-memory", "52428800" },
{ "version", "7.14" },
}),
new TikFakeDoneSentence(),
});
ITikReSentence row = conn.CreateCommand("/system/resource/print").ExecuteSingleRow();
Assert.AreEqual("12", row.GetResponseField("cpu-load"));Async commands (torch, listen, …) call CallCommandAsync on a background thread.
Register the sentences exactly as for sync — they will be delivered via callback:
var received = new List<string>();
var done = new ManualResetEventSlim(false);
var conn = new TikFakeConnection()
.WithResponse(
rows => rows.First() == "/tool/torch",
new ITikSentence[]
{
new TikFakeReSentence(new Dictionary<string, string> { { "tx", "1000" }, { "rx", "500" } }),
new TikFakeReSentence(new Dictionary<string, string> { { "tx", "2000" }, { "rx", "800" } }),
new TikFakeDoneSentence(),
});
ITikCommand torchCmd = conn.CreateCommand("/tool/torch",
conn.CreateParameter("interface", "ether1"));
torchCmd.ExecuteAsync(
oneResponseCallback: re => received.Add(re.GetResponseField("tx")),
onDoneCallback: () => done.Set());
done.Wait(TimeSpan.FromSeconds(2));
Assert.AreEqual(new[] { "1000", "2000" }, received);TikCommandTrapException is thrown by all Execute* methods when a !trap is present:
var conn = new TikFakeConnection()
.WithTrap(
predicate: rows => rows.First() == "/ip/address/add",
message: "already have such item");
ITikCommand cmd = conn.CreateCommandAndParameters("/ip/address/add",
"address", "10.0.0.1/24", "interface", "ether1");
Assert.ThrowsException<TikCommandTrapException>(() => cmd.ExecuteNonQuery());