简体   繁体   English

单元测试-数据库数据

[英]Unit testing - database data

I tried creating unit tests for some methods that has stored procedures. 我尝试为具有存储过程的某些方法创建单元测试。 Below are the questions i have. 以下是我的问题。

  • How to unit test a project that uses lot of stored procedures to get the data from database for validations? 如何对使用大量存储过程从数据库中获取数据进行验证的项目进行单元测试?

    • If i have to call those methods from my unit test, i am actually making n no of database calls...Is it worth it? 如果我必须从单元测试中调用这些方法,则实际上我没有进行数据库调用...这值得吗?

    • If i have to use the mock data, how to get the copy of the data from database locally? 如果我必须使用模拟数据,如何从本地数据库获取数据副本?

    • How to mimic the stored procedure calls to use the mock data? 如何模仿存储过程调用以使用模拟数据?

You're looking at integration tests, not unit tests. 您正在查看集成测试,而不是单元测试。 Integration tests have a dependency from an external system (datetime, database, filesystem, networkservice, etc) while unit tests their scope is confined to one unit (one or more methods in one or more classes). 集成测试具有来自外部系统(日期时间,数据库,文件系统,网络服务等)的依赖关系,而单元测试的范围则限于一个单元(一个或多个类中的一种或多种方法)。

The first thing to realize here is that in order to do an integration test, you will be relying on an external system. 在这里首先要意识到的是,为了进行集成测试,您将依赖于外部系统。 You never want to test against your production environment and you want to maintain control over the test data. 您永远都不想在生产环境中进行测试,并且想要保持对测试数据的控制。

For this reason you should create a database that is exactly the same as your existing one but is stripped of all data and uses mock data instead. 因此,您应该创建一个与现有数据库完全相同的数据库,但该数据库将删除所有数据并使用模拟数据。 This makes sure that your tests will stay consistent throughout changes and thus can be relied upon. 这样可以确保您的测试在所有更改中都保持一致,从而可以得到依赖。
You should also remember to keep your test database functionally equivalent to your live database to avoid falling behind and having outdated tests. 您还应该记住,要使测试数据库在功能上与实时数据库保持一致,以避免落后和落后于测试。

What's key here is this: abstract your data source layer . 这里的关键是: 抽象数据源层 If you put all your database calls behind an interface, you can simply mock/stub this interface and provide test data from there. 如果将所有数据库调用都放在一个接口后面,则可以仅对该接口进行模拟/存根并从那里提供测试数据。

Your unit of work should be to the point and test the one thing the method is supposed to do (Single Responsibility Principle). 您的工作单位应该是重点,并测试该方法应做的一件事(单一责任原则)。
If the objective of your method is to manipulate data from the database then you mock your data source and you unit test your manipulation. 如果您的方法的目的是要操纵数据库中的数据,那么您可以模拟数据源并进行单元测试。
If the objective of your method is to call a stored procedure in your database, then you use your integration test to feed the procedure input and assert against its output. 如果方法的目的是在数据库中调用存储过程,则可以使用集成测试来输入过程输入并对其输出进行断言。

A simple example of this principle in action: 这个原则在行动中的简单示例:

interface DataSource {
    List<String> GetData();
}

class Manipulator {
    private DataSource _source;

    public Manipulator() { }

    public Manipulator(DataSource d) { _source = d; }

    public void ManipulateData() {
        var data = _source.GetData();

        // Do something with the data
    }
}

This sample utilizes constructor injection (look into the concepts of dependency injection and IoC containers!). 该示例利用了构造函数注入(请查看依赖注入和IoC容器的概念!)。

Now to answer your questions to the point: 现在回答您的问题:

If i have to call those methods from my unit test, i am actually making n no of database calls...Is it worth it? 如果我必须从单元测试中调用这些方法,则实际上我没有进行数据库调用...这值得吗?

Yes, otherwise you don't have an integration test. 是的,否则您没有集成测试。 Since you have a separate test database this will not interfere with your production environment. 由于您具有单独的测试数据库,因此不会干扰您的生产环境。

If i have to use the mock data, how to get the copy of the data from database locally? 如果我必须使用模拟数据,如何从本地数据库获取数据副本?

I'm not quite sure what you're asking here to be honest, but I think it is resolved with the idea of a testing database. 我不太确定您在说的是什么,但是我认为可以通过测试数据库的想法解决。

How to mimic the stored procedure calls to use the mock data? 如何模仿存储过程调用以使用模拟数据?

You don't. 你不知道 You use the actual stored procedures by calling them with your test data and asserting the result on what you expect. 您可以使用实际的存储过程,方法是将它们与测试数据一起调用,并根据期望声明结果。 If they work then that's the end of it, if they don't return the correct result then you know something went wrong. 如果他们工作了,那就结束了,如果他们没有返回正确的结果,那么您就知道出了点问题。

You need to define an interface that has all of your data access methods. 您需要定义一个包含所有数据访问方法的interface You already have one class with those methods, so you can simply refactor it in Visual Studio by right clicking in an empty space in your data access class and select Refactor and then Extract Interface . 您已经具有使用这些方法的一个类,因此您可以在Visual Studio中通过在数据访问类中的空白处单击鼠标右键,然后选择RefactorExtract Interface来对其进行 重构 So now you have an interface , you need to add a mock data access class that implements that interface . 因此,现在您有了一个interface ,您需要添加一个实现该interface的模拟数据访问类。

In doing this, your mock data access class doesn't need to know anything about any stored procedures as long as it returns some data of the correct types specified by the interface . 为此,您的模拟数据访问类不需要知道任何存储过程,只要它返回interface指定的正确类型的interface The last part is to pass an instance of the actual data access class when using the application and for testing, pass an instance of the mock data access class instead. 最后一部分是在使用应用程序时传递实际数据访问类的实例,并进行测试,而是传递模拟数据访问类的实例。

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

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