如何使用C#进行单元测试SQL查询,而不影响或操作真实数据库。

huangapple go评论76阅读模式
英文:

How to Unit Test Sql Queries without affecting or manipulating real Database with c#

问题

I'm using moq framework for unit test my C# code. its working good with ef core and its objects, but I also have some sql queries in my code that I have to include in Unit Testing process. below is my method which contains some sql scripts, I want to run this script in unit testing but without affecting on real database.

public void DeleteContentData(string connectionString)
{
   using IDbConnection db = new SqlConnection(connectionString);
   DynamicParameters dynParameters1 = new DynamicParameters();
   dynParameters1.Add("@contentId", _content.content_id);
   db.Execute("DELETE FROM [content] WHERE content_id=@contentId", dynParameters1);
   db.Execute("INSERT INTO [content] (content_id) VALUES (@contentId);", dynParameters1);
}

How can I execute this method and run sql scripts without delete records and insert new records in unit testing.

英文:

I'm using moq framework for unit test my C# code. its working good with ef core and its objects, but I also have some sql queries in my code that I have to include in Unit Testing process. below is my method which contains some sql scripts, I want to run this script in unit testing but without affecting on real database.

public void DeleteContentData(string connectionString)
{
   using IDbConnection db = new SqlConnection(connectionString);
   DynamicParameters dynParameters1 = new DynamicParameters();
   dynParameters1.Add("@contentId", _content.content_id);
   db.Execute("DELETE FROM [content] WHERE content_id=@contentId", dynParameters1);
   db.Execute("INSERT INTO [content] (content_id) VALUES (@contentId);", dynParameters1);
}

How can I execute this method and run sql scripts without delete records and insert new records in unit testing.

答案1

得分: 0

以下是您要翻译的内容:

Instead of passing a connection string, you have to pass the dbconnection:

public void DeleteContentData(IDbConnection db)
{
   DynamicParameters dynParameters1 = new DynamicParameters();
   dynParameters1.Add("@contentId", _content.content_id);
   db.Execute("DELETE FROM [content] WHERE content_id=@contentId", dynParameters1);
   db.Execute("INSERT INTO [content] (content_id) VALUES (@contentId);", dynParameters1);
}

You can keep an overloaded version of the method where you have the connection string as a parameter. That way, you don't have to change all the calls of your method:

public void DeleteContentData(string connectionString)
{
   using IDbConnection db = new SqlConnection(connectionString);
   DeleteContentData(db);
}

For your unit test, you create a mock of your `IDbConenction`. You call your method with this mocked instance and in the end of the test, you check whether the `Execute` methods where called correctly. I don't know your class under test and the `DynamicParameters` class, hence I can only guess how the test might look. But maybe this way:

[TestMethod]
public void TestDeleteContentData()
{
  // arrange
  var db = new Mock<IDbConenction>();
  var classUnderTest = new ClassUnderTest();
  classUnderTest._content.content_id = 5;

  // act
  classUnderTest.DeleteContentData(db.Object);

  // assert
  db.Verify(x => x.Execute("DELETE FROM [content] WHERE content_id=@contentId", It.Is<DynamicParameters>(y => y.Contains("@contentId",5)));
}
英文:

Instead of passing a connection string, you have to pass the dbconnection:

public void DeleteContentData(IDbConnection db)
{
   DynamicParameters dynParameters1 = new DynamicParameters();
   dynParameters1.Add(&quot;@contentId&quot;, _content.content_id);
   db.Execute(&quot;DELETE FROM [content] WHERE content_id=@contentId&quot;, dynParameters1);
   db.Execute(&quot;INSERT INTO [content] (content_id) VALUES (@contentId);&quot;, dynParameters1);
}

You can keep an overloaded version of the method where you have the connection string as a parameter. That way, you don't have to change all the calls of your method:

public void DeleteContentData(string connectionString)
{
   using IDbConnection db = new SqlConnection(connectionString);
   DeleteContentData(db);
}

For your unit test, you create a mock of your IDbConenction. You call your method with this mocked instance and in the end of the test, you check whether the Execute methods where called correctly. I don't know your class under test and the DynamicParameters class, hence I can only guess how the test might look. But maybe this way:

[TestMethod]
public void TestDeleteContentData()
{
  // arrange
  var db = new Mock&lt;IDbConenction&gt;();
  var classUnderTest = new ClassUnderTest();
  classUnderTest._content.content_id = 5;

  // act
  classUnderTest.DeleteContentData(db.Object);

  // assert
  db.Verify(x =&gt; x.Execute(&quot;DELETE FROM [content] WHERE content_id=@contentId&quot;, It.Is&lt;DynamicParameters&gt;(y =&gt; y.Contains(&quot;@contentId&quot;,5)));
}

答案2

得分: 0

我认为,如果在不实际访问数据库的情况下测试此类代码是否有意义,以及如果它们实际上访问了数据库,它们是否可以称为单元测试,这仍然是一个有争议的问题。

如果你仍然想遵循不访问数据库的方法,那么你需要重构代码,以便可以注入IDbConnection(可以通过构造函数或方法参数),并传递一个具有相应方法的模拟实例。

如果你想验证代码实际工作,有两个主要选项:

  1. 从单元测试切换到集成测试,并访问实际数据库,验证所需的内容是否已删除。
  2. 使用test containers - 在容器中启动一个一次性数据库实例,并对其进行操作。
英文:

I would say it up for debate if there is a point of testing such code without actually hitting database and if they can be called unit tests if they actually hit one.

Still if you want to follow the approach without hitting the database then you will need to refactor the code so IDbConnection can be injected (either via ctor or method parameter) and pass a mocked instance with corresponding methods mocked.

If you want to verify that the code actually works there are two main options:

  1. Switch from unit tests to integration ones and hit actual database and validate that what is needed is deleted
  2. Use test containers - spin up a throwaway db instance in container and do with it whatever you want.

答案3

得分: 0

我在这篇文章中找到了最适合我的单元测试SQL查询的解决方案:https://www.codeproject.com/Articles/5332010/Unit-Test-Your-Database-Classes。

这篇文章还包含了供参考的演示项目,还有一个YouTube视频:https://www.youtube.com/watch?v=ta4ZVLPra5E。

如果有人在尝试找到一种好的方法来单元测试你的SQL查询,可以按照这篇文章进行操作。如果有人遇到问题,可以告诉我,我可以提供帮助。

英文:

I found the Best suitable solution for me to Unit Test SQL Queries in this article: https://www.codeproject.com/Articles/5332010/Unit-Test-Your-Database-Classes.

This article also contains demo project for reference and also has a video on YouTube: https://www.youtube.com/watch?v=ta4ZVLPra5E

You can follow this article if trying to figure out a good way to Unit Test your Sql Queries. Let me know if someone facing issues, I can help.

huangapple
  • 本文由 发表于 2023年7月20日 13:34:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/76726935.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定