简体   繁体   English

单元测试SQL字符串

[英]Unit testing a sql string

Short Question 简短问题

Is there something you can run sql commands that have JOINS and WHEREs that is not a DB 有什么可以运行具有JOINS和WHERE而不是DB的sql命令的

Long Question 长问题

I am putting in unit tests for a brown field win forms app. 我正在为一个棕色领域获胜表格应用程序进行单元测试。 I have complete freedom of choice on what kinda unit test framework I have 对于哪种单元测试框架,我拥有完全的选择自由

The problem I have is there is masses of SQL string statement in the code. 我的问题是代码中有大量的SQL字符串语句。 Think something like this 这样想

SELECT *
FROM Sale 
INNER JOIN SaleItem ON Sale.ID = SaleItem.SaleID
WHERE ID = 5

It is parameterized, and has IF statements to build up the where, so it might be where CustomerId = 5 or DispatchDate was in last year. 它已参数化,并且具有IF语句来建立where,因此可能是去年的CustomerId = 5或DispatchDate。 The query is a lot bigger that this, and I kinda want to check that all the joins work and all the possible wheres work. 这个查询要大得多,我有点想检查所有联接是否起作用以及所有可能的位置。 Do think this might be me looking at the detail to much 认为这可能是我过多地关注细节

I dont want to have to manage a database of data, which if the data changes it will break tests, and I'm scared that will root and people will just kill of the tests. 我不想管理一个数据数据库,如果数据更改,它将破坏测试,而且我担心这会生根,人们只会扼杀测试。

I want to run this sql against some object or a thing, that is NOT a DB and get a item. 我想针对某些对象或东西(不是数据库)运行此sql并获取一项。 It has to be smart enough to actually filter So it the Sale object was like the following table, it would only return the one with the ID 5. 它必须足够聪明以实际进行过滤,因此,Sale对象类似于下表,它将仅返回ID为5的对象。

ID DateDispatched CustomerID
1  1/1/1          5   
2  2/2/2          6   
5  3/3/3          7 

I have thought of running sql command on datasets and XML, and relised that wont work. 我曾考虑过在数据集和XML上运行sql命令,并且认为这行不通。 I guess LINQ has spoiled me over that last few years cus I cant work out how to do this. 我想LINQ在过去几年让我宠坏了,因为我无法解决该怎么做。 And im afraid there is so much logic building up massive SQL statement, I have to put some tests on them. 而且恐怕要建立大量SQL语句的逻辑太多,我必须对它们进行一些测试。

Would be more than willing to hear about other options like moving the SQL to stored procedure in the DB, if you can recommend a good unit testing framework. 如果您可以推荐一个好的单元测试框架,那么您将不愿意听到其他选择,例如将SQL移至数据库中的存储过程。

Now I don't like SQL being built in the app and would love to change it to entity framework, but its a 10 year old application and that's just not a option. 现在,我不喜欢在应用程序中内置SQL,而是希望将其更改为实体框架,但是它已有10年的历史了,这不是一个选择。

Okay some quick edits The database is on SQL Server 2012, so stored procedures are a option, as in some places they use stored procedures. 好的快速编辑数据库位于SQL Server 2012上,因此存储过程是一个选择,因为在某些地方它们使用存储过程。

Let me try to understand your problem. 让我尝试了解您的问题。

You have got an winform application and you are writing unit tests for this. 您已经有一个winform应用程序,并且正在为此编写单元测试。 But if you run the the test, you afraid it will going to hit the DB and spoil the data. 但是,如果运行测试,您担心它会击中数据库并破坏数据。 So you want some mechanism which allows to run your unit tests but will not hit the actual database. 因此,您需要一种允许运行单元测试但不会影响实际数据库的机制。 Correct? 正确?

If I got your problem right, I suggest to separate out your db interaction logic and make it interface driven. 如果我的问题正确,建议您分离出数据库交互逻辑,并使其成为接口驱动。 Then you can create mock objects, wherein you define the expectation of your db interaction interfaces. 然后,您可以创建模拟对象,在其中定义数据库交互接口的期望。 So for example, if some GetSales() method is called, what should be returned from this method? 因此,例如,如果调用了某些GetSales()方法,则该方法应返回什么? and so on. 等等。 Sharing some links on details about unit testing and mocking. 共享一些有关单元测试和模拟的详细信息的链接。

https://msdn.microsoft.com/en-us/library/ff650441.aspx https://msdn.microsoft.com/en-us/library/ff650441.aspx

https://github.com/Moq/moq4 https://github.com/Moq/moq4

http://www.developerhandbook.com/unit-testing/writing-unit-tests-with-nunit-and-moq/ http://www.developerhandbook.com/unit-testing/writing-unit-tests-with-nunit-and-moq/

Testing a MVC Controller fails with NULL reference exception 测试MVC控制器失败,并出现NULL引用异常

A SQLite database is designed for exactly this kind of requirement. SQLite数据库正是为这种需求而设计的。

The database is a simple file. 该数据库是一个简单的文件。 The database driver reads from and writes to this file. 数据库驱动程序从该文件读取和写入。 You can run all the SQL queries and so on that you are used to against the database. 您可以运行所有用于数据库的SQL查询等等。 (However, you might have problems if your SQL uses language or syntax specific to SQL Server.) (但是,如果您的SQL使用特定于SQL Server的语言或语法,则可能会遇到问题。)

It is true that you have to manage a 'database' full of data. 确实,您必须管理一个充满数据的“数据库”。 But you should be able to: 但是您应该能够:

  • Write a script which quickly sets up all the tables. 编写一个可以快速设置所有表的脚本。 You might already have a piece of code which create a database with the same schema, or you might be able to dump one automatically. 您可能已经有一段代码可以创建具有相同架构的数据库,或者您可以自动转储一个数据库。
  • Keep some test data around in CSV's, SQL files, or similar. 将一些测试数据保存在CSV,SQL文件或类似文件中。 This isn't easy, but it is very very useful. 这并不容易,但是非常有用。 You should add the minimum and only build it up as the testing demands. 您应该添加最小值,并仅根据测试要求进行构建。
  • Check the whole SQLite database file into source control if you like. 如果愿意,可以将整个SQLite数据库文件检入源代码管理。

Thanks for the question - I have been thinking a lot about testable database code recently, and I hadn't figured out a solution to this type of problem until your question made me realize I already knew it. 谢谢您提出这个问题-最近我一直在思考可测试的数据库代码,直到您的问题使我意识到我已经知道为止,我才想出解决此类问题的方法。

In my opinion, there are three approaches to make this kind of testing as painless as possible in the long-run: 我认为,从长远来看,可以通过三种方法使这种测试尽可能轻松:

  1. Use an ORM or another wrapper layer, such as Entity Framework as you mentioned. 使用ORM或另一个包装层,例如您提到的Entity Framework。 This means that when testing you don't need a 'real database' at all - just a test double of your wrapper. 这意味着在测试时,您根本不需要“真实数据库”,只需包装的两倍即可。
  2. Only use standard portable SQL such as JOIN, SELECT, etc, with nothing which can't be run on a SQLite database. 仅使用标准的可移植SQL(例如JOIN,SELECT等),而不能在SQLite数据库上运行。 This can be very restrictive, as types vary so much between DBMS. 这可能非常严格,因为DBMS之间的类型差异很大。
  3. Use SPs exclusively as an interface to your database. 仅将SP用作数据库的接口。 This means that your test double only has to recognize which SP is being called, and respond correctly to that. 这意味着您的测试双精度只需要识别正在调用哪个SP,并对此做出正确响应。 I personally don't like this approach as I think lots of untested, unversioned business logic ends up in the SPs. 我个人不喜欢这种方法,因为我认为许多未经测试,未经版本控制的业务逻辑最终会出现在SP中。

Here is an option that we use for our unit testing with MS test 这是我们用于MS测试的单元测试的选项

Use the TransactionScope from the System.Transactions namespace in your TestInitialize method Create an instance of the transaction and in the TestCleanup method dispose of it. 在TestInitialize方法中使用System.Transactions命名空间中的TransactionScope,创建事务的实例,并在TestCleanup方法中处理它。 You can do the insert into the db in the test initialize method or in the individual test methods 您可以在测试初始化​​方法或单个测试方法中插入数据库

[TestCleanup]  
public void testClean()  
{  
    _Trans.Dispose();

} 


[TestInitialize]  
public void testInit()  
{  
    _Trans = new TransactionScope(); 
}   

[TestMethod]
public void TestQuery()
{
    // arrange
    //' insert data
    // act
    Obj Target = Obj.New();
    // Assert
    Assert.AreEqual("someValue",Obj.SomeProperty);
}

Okay I took the old adage of if you cant change your employer, change your employer. 好吧,如果您不能更换雇主,请更换雇主。

I think tsqlt http://tsqlt.org/ would of been the best fit for this exact problem. 我认为tsqlt http://tsqlt.org/最适合这个确切的问题。

As Entity framework would not be allowed and they had so many dependency tables. 由于不允许使用实体框架,因此它们具有太多的依赖表。 Which would let me mock tables move all logic to stored procedures and mock the tables. 这会让我模拟表将所有逻辑移至存储过程并模拟表。 Kinda mix of Yogi and JWG answer. 瑜伽士和JWG的回答有点混搭。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM