如何正确地对存储库上的 CRUD 操作进行单元测试?

发布于 2024-09-28 10:16:28 字数 1873 浏览 0 评论 0原文

意识到这听起来像是一个广泛的问题 - 所以让我澄清一下。我有一个通过接口公开的存储库,有两个具体实现 - 一个 MockRepository 和一个 EntityFrameworkRepository

现在,我有一个单元测试项目,通过轻拂 [TestInitialize] 中的一行,可以针对任一存储库运行所有测试。

我的问题基本上是“我应该如何编写测试”。

这就是我所拥有的:

C reate

// Arrange.
var foo = new Foo { .. };

// Act
Repository.Add(foo);
UnitOfWork.Commit();

// Assert
Assert.IsTrue(foo.Id > 0);

R etrieve

// Arrange.
var fooToGet = 1;

// Act
var foo = Repository.FindSingle(fooToGet);

// Assert
Assert.IsNotNull(foo);
Assert.AreEqual(foo.Id, fooToGet);

U pdate

// Arrange.
var fooToGet = 1;
var nameToChangeFooTo = "FooBar";

// Act
var foo = Repository.FindSingle(fooToGet);
foo.Name = nameToChangeFooTo;
UnitOfWork.Commit();
var fooRetrievedAgain = Repository.FindSingle(fooToGet);

// Assert
Assert.IsNotNull(foo);
Assert.AreEqual(fooRetrievedAgain.Id, fooToGet);
Assert.AreEqual(fooRetrievedAgain.Name, nameToChangeFooTo);

D elete

// Arrange.
var fooToGet = 1;

// Act
var foo = Repository.FindSingle(fooToGet);
Repository.Remove(foo);
UnitOfWork.Commit();
var fooRetrievedAgain = Repository.FindSingle(fooToGet);

// Assert
Assert.IsNull(fooRetrievedAgain);

工作正常ok,对于 Mock 和 EF 存储库,但我的主要问题是 C(创建)。我不确定如何在我的存储库上测试添加操作。我所做的事情感觉不对

它传递给 EF 存储库,但为了使其传递到我的模拟存储库中,我必须使用反射来更新内存集合中的 ID(令人讨厌)。

那么 - 您能否分享一些关于在存储库模式上测试 CRUD 操作的正确方法的建议?

这是一个 ASP.NET MVC 应用程序、.NET 4、C#、Entity Framework 4 和工作单元/存储库模式。

谢谢。

编辑

只是为了澄清大家,这些并不是我拥有的全部单元测试。我有服务层的单元测试以及业务规则测试。

如果我的上述存储库测试失败,后者都会(并且应该)失败。这就是这里的重点,对我的存储库的非常基本的操作进行单元测试。我错了吗?

Realize this may sound like a broad question - so let me clarify. I have a Repository exposed via an interface, with two concrete implementations - a MockRepository and a EntityFrameworkRepository.

Now, i have a Unit-Test project for which all tests can be run against either repository, via flicking over a line in [TestInitialize].

My question is basically "How should i write the tests".

Here's what i have:

C reate

// Arrange.
var foo = new Foo { .. };

// Act
Repository.Add(foo);
UnitOfWork.Commit();

// Assert
Assert.IsTrue(foo.Id > 0);

R etrieve

// Arrange.
var fooToGet = 1;

// Act
var foo = Repository.FindSingle(fooToGet);

// Assert
Assert.IsNotNull(foo);
Assert.AreEqual(foo.Id, fooToGet);

U pdate

// Arrange.
var fooToGet = 1;
var nameToChangeFooTo = "FooBar";

// Act
var foo = Repository.FindSingle(fooToGet);
foo.Name = nameToChangeFooTo;
UnitOfWork.Commit();
var fooRetrievedAgain = Repository.FindSingle(fooToGet);

// Assert
Assert.IsNotNull(foo);
Assert.AreEqual(fooRetrievedAgain.Id, fooToGet);
Assert.AreEqual(fooRetrievedAgain.Name, nameToChangeFooTo);

D elete

// Arrange.
var fooToGet = 1;

// Act
var foo = Repository.FindSingle(fooToGet);
Repository.Remove(foo);
UnitOfWork.Commit();
var fooRetrievedAgain = Repository.FindSingle(fooToGet);

// Assert
Assert.IsNull(fooRetrievedAgain);

It's working ok, for both the Mock and EF repository, but my main problem is C (Create). I'm not sure how to test an Add operation on my Repository. It doesn't feel right what im doing.

It passes for the EF Repository, but to make it pass in my Mock Repository i had to use reflection to update the ID in the in-memory collection (nasty).

So - can you please share some advice on what are the correct ways to test CRUD operations on the Repository Pattern?

This is an ASP.NET MVC Application, .NET 4, C#, Entity Framework 4 and Unit of Work/Repository Patterns.

Thanks.

EDIT

Just to clarify guys, these are not all the unit-tests i have. I have unit tests for my service layer, as well as business-rule tests.

Both the latter will (and should) fail if my above Repository tests fail. That is the point here, to unit-test the very basic operations of my Repositories. Am i wrong?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

牵你的手,一向走下去 2024-10-05 10:16:28

一种选择是使用 SqlLite 等内存数据库来测试映射、查询和存储库的行为。 Ayende 此处对此进行了讨论,尽管他的示例使用 NHibernate。

另一个选项似乎可以解决您对设置域对象 ID 的直接关注,那就是使用测试假货。 RhysC 此处对此进行了讨论。

One option is to use an in-memory DB like SqlLite to test the behaviour of your mappings, queries and repositories. This is discussed by Ayende here, though his example uses NHibernate.

Another option which seems to address your immediate concern of setting the Ids of the domain objects is to use test fakes. This is discussed by RhysC here.

余罪 2024-10-05 10:16:28

IMO,您的创建测试应该:

  • 将一个实体添加到存储库
  • 断言它已分配一个 ID
  • 使用 ID 检索插入的实体
  • 将初始实体与读取实体进行比较,并确保它们的属性相同

我有很多像您这样的单元测试主要区别在于我使用深度比较方法来比较对象实例。例如,我的 U 测试如下所示:

  • 将实体添加到存储库
  • 使用 ID 检索插入的实体 更改
  • 某些实体属性
  • 更新存储库中的实体
  • 使用 ID 检索更新的实体
  • 将更新的实体与读取的实体进行比较并确保它们的属性相同(您可以为不可更新的属性定义特定逻辑)

IMO, your create test should:

  • add an entity to the repository
  • assert it was assigned an ID
  • retrieve the inserted entity using the ID
  • compare the initial entity with the read entity and make sure their properties are same

I've got many unit tests like yours the main difference is that I'm using a deep comparison method to compare object instances. For instance, my U tests look like this:

  • add an entity to the repository
  • retrieve the inserted entity using the ID
  • change some of the entity properties
  • update the entity in the repository
  • retrieve the updated entity using the ID
  • compare the updated entity with the read entity and make sure their properties are same (you can define a specific logic for properties that are not updatable)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文