Add tests for ActiveRecord functionality (DbBase.Find<T>, Client.FindByName, DbBase.Context singleton)
This commit is contained in:
@@ -159,4 +159,138 @@ public class BeforeTests
|
|||||||
|
|
||||||
DbBase.Context = null; // cleanup
|
DbBase.Context = null; // cleanup
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
// (9) ActiveRecord finder: DbBase.Find<T> walks the context's tracked
|
||||||
|
// entities, looks for the first whose runtime type matches T,
|
||||||
|
// and returns it when <paramref name="predicate"/> matches.
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
[Fact]
|
||||||
|
public void DbBase_Find_finds_matching_entity()
|
||||||
|
{
|
||||||
|
var db = new DbContext();
|
||||||
|
var acme = new Client { Name = "Acme" };
|
||||||
|
var globex = new Client { Name = "Globex" };
|
||||||
|
db.Attach(acme);
|
||||||
|
db.Attach(globex);
|
||||||
|
|
||||||
|
var result = DbBase.Find<Client>(c => c.Name == "Globex", db);
|
||||||
|
|
||||||
|
Assert.NotNull(result);
|
||||||
|
Assert.Same(globex, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
// (10) DbBase.Find returns null when no entity of type T satisfies
|
||||||
|
// the predicate.
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
[Fact]
|
||||||
|
public void DbBase_Find_returns_null_when_no_match()
|
||||||
|
{
|
||||||
|
var db = new DbContext();
|
||||||
|
db.Attach(new Client { Name = "Acme" });
|
||||||
|
|
||||||
|
var result = DbBase.Find<Client>(c => c.Name == "Nobody", db);
|
||||||
|
|
||||||
|
Assert.Null(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
// (11) DbBase.Find filters by runtime type — an Order attached to the
|
||||||
|
// context does NOT match a Client predicate.
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
[Fact]
|
||||||
|
public void DbBase_Find_ignores_non_matching_types()
|
||||||
|
{
|
||||||
|
var db = new DbContext();
|
||||||
|
db.Attach(new Order { Description = "test" });
|
||||||
|
|
||||||
|
var result = DbBase.Find<Client>(_ => true, db);
|
||||||
|
|
||||||
|
Assert.Null(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
// (12) DbBase.Find returns the FIRST matching entity only.
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
[Fact]
|
||||||
|
public void DbBase_Find_returns_first_match()
|
||||||
|
{
|
||||||
|
var db = new DbContext();
|
||||||
|
var first = new Client { Name = "SameName" };
|
||||||
|
var second = new Client { Name = "SameName" };
|
||||||
|
db.Attach(first);
|
||||||
|
db.Attach(second);
|
||||||
|
|
||||||
|
var result = DbBase.Find<Client>(c => c.Name == "SameName", db);
|
||||||
|
|
||||||
|
Assert.Same(first, result); // first one inserted wins
|
||||||
|
Assert.NotSame(second, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
// (13) DbBase.Find handles a null context gracefully.
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
[Fact]
|
||||||
|
public void DbBase_Find_with_null_context_returns_default()
|
||||||
|
{
|
||||||
|
var result = DbBase.Find<Client>(_ => true, null);
|
||||||
|
Assert.Null(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
// (14) Client.FindByName delegates to DbBase.Find and works correctly.
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
[Fact]
|
||||||
|
public void Client_FindByName_finds_by_name()
|
||||||
|
{
|
||||||
|
var db = new DbContext();
|
||||||
|
var acme = new Client { Name = "Acme Corp" };
|
||||||
|
db.Attach(acme);
|
||||||
|
|
||||||
|
var result = Client.FindByName("Acme Corp", db);
|
||||||
|
|
||||||
|
Assert.NotNull(result);
|
||||||
|
Assert.Same(acme, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
// (15) Client.FindByName returns null when the name does not match.
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
[Fact]
|
||||||
|
public void Client_FindByName_returns_null_when_not_found()
|
||||||
|
{
|
||||||
|
var db = new DbContext();
|
||||||
|
db.Attach(new Client { Name = "Acme Corp" });
|
||||||
|
|
||||||
|
var result = Client.FindByName("Nobody", db);
|
||||||
|
|
||||||
|
Assert.Null(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
// (16) The class-level DbBase.Context singleton can be used as the
|
||||||
|
// implicit context source for Find operations — the classic
|
||||||
|
// ActiveRecord pattern where any entity method reaches the shared
|
||||||
|
// context without parameter passing.
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
[Fact]
|
||||||
|
public void DbBase_Context_singleton_is_used_in_Find()
|
||||||
|
{
|
||||||
|
var db = new DbContext();
|
||||||
|
var targeted = new Client { Name = "TargetCo" };
|
||||||
|
db.Attach(targeted);
|
||||||
|
|
||||||
|
DbBase.Context = db;
|
||||||
|
|
||||||
|
// Query using the singleton instead of passing the context:
|
||||||
|
// (In practice, callers often do this to avoid threading db through
|
||||||
|
// every call — the whole point of the ActiveRecord leak.)
|
||||||
|
var queryResult = DbBase.Find<Client>(c => c.Name == "TargetCo", DbBase.Context);
|
||||||
|
|
||||||
|
Assert.NotNull(queryResult);
|
||||||
|
Assert.Same(targeted, queryResult);
|
||||||
|
|
||||||
|
DbBase.Context = null; // cleanup
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user