-
Notifications
You must be signed in to change notification settings - Fork 100
Testing low 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 mid-level API · Testing high-level API
TikFakeConnection intercepts at CallCommandSync — the lowest point in the call stack — so every
higher layer runs through real code. At this level you work directly with raw MikroTik sentence
arrays and inspect command rows verbatim.
using tik4net;
using tik4net.Testing;Add tik4net.testing as a NuGet/project reference in your test project. No router or network
connection is required.
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.
Use WithResponse(predicate, sentences) to register a handler.
The first matching handler wins (registration order).
var conn = new TikFakeConnection()
.WithResponse(
predicate: rows => rows.First() == "/interface/print",
sentences: new ITikSentence[]
{
new TikFakeReSentence(new Dictionary<string, string>
{
{ ".id", "*1" },
{ "name", "ether1" },
{ "type", "ether" },
{ "running", "true" },
{ "disabled", "false" },
}),
new TikFakeReSentence(new Dictionary<string, string>
{
{ ".id", "*2" },
{ "name", "ether2" },
{ "type", "ether" },
{ "running", "false" },
{ "disabled", "false" },
}),
new TikFakeDoneSentence(),
});
// Execute the code under test
string[] command = new string[] { "/interface/print" };
IEnumerable<ITikSentence> result = conn.CallCommandSync(command);
// Assert
var reRows = result.OfType<ITikReSentence>().ToList();
Assert.AreEqual(2, reRows.Count);
Assert.AreEqual("ether1", reRows[0].GetResponseField("name"));When the response should depend on the actual command rows (e.g. to echo back a filter value),
use the overload that accepts Func<IEnumerable<string>, IEnumerable<ITikSentence>>:
var conn = new TikFakeConnection()
.WithResponse(
predicate: rows => rows.First() == "/ip/address/print",
response: rows =>
{
// rows may contain filter parameters like "?.id=*1"
bool filtered = rows.Any(r => r.Contains(".id=*1"));
var result = new List<ITikSentence>();
if (!filtered || rows.Any(r => r == "?.id=*1"))
result.Add(new TikFakeReSentence(new Dictionary<string, string>
{ { ".id", "*1" }, { "address", "10.0.0.1/24" } }));
result.Add(new TikFakeDoneSentence());
return result;
});var conn = new TikFakeConnection()
.WithTrap(
predicate: rows => rows.First() == "/ip/address/add",
message: "already have such item");
// CallCommandSync returns the trap sentence; Execute* methods throw TikCommandTrapException
IEnumerable<ITikSentence> result = conn.CallCommandSync("/ip/address/add", "=address=10.0.0.1/24");
Assert.IsTrue(result.OfType<ITikTrapSentence>().Any());SentCommands records every command row array in order.
conn.AssertWasSent("/interface/print");
// Fine-grained: check that a specific parameter was included
conn.AssertWasSent(rows => rows.Any(r => r == "=name=ether1"));
// Count calls (e.g. ensure /set was called exactly once)
Assert.AreEqual(1, conn.GetCallCount("/ip/address/set"));Register a catch-all last to avoid InvalidOperationException on unexpected commands:
var conn = new TikFakeConnection()
.WithResponse(rows => rows.First() == "/system/identity/print",
new ITikSentence[] { new TikFakeReSentence(...), new TikFakeDoneSentence() })
// catch-all: every other command succeeds silently
.WithNonQuery(rows => true);