Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Asp.net mvc 如何实现/构建/创建';内存数据库';对于我的单元测试_Asp.net Mvc_Database_Unit Testing - Fatal编程技术网

Asp.net mvc 如何实现/构建/创建';内存数据库';对于我的单元测试

Asp.net mvc 如何实现/构建/创建';内存数据库';对于我的单元测试,asp.net-mvc,database,unit-testing,Asp.net Mvc,Database,Unit Testing,我在不久前开始了单元测试,结果证明我做了比单元测试更多的回归测试,因为我还包括了我的数据库层,因此每次都要访问数据库 因此,实现了Unity以注入一个伪数据库层,但我当然想存储一些数据,主要观点是:“创建内存中的数据库” 但这是什么/我如何实现 主要的问题是:我认为我必须伪造数据库层,但这不是让我自己创建一个“简单数据库”吗?或者:我如何保持它的简单,而不只是为了单元测试而重建Sql Server:) 在这个问题的最后,我将解释一下我刚刚开始的项目的情况,我想知道这是否是一条路要走 米歇尔 我在

我在不久前开始了单元测试,结果证明我做了比单元测试更多的回归测试,因为我还包括了我的数据库层,因此每次都要访问数据库

因此,实现了Unity以注入一个伪数据库层,但我当然想存储一些数据,主要观点是:“创建内存中的数据库”

但这是什么/我如何实现

主要的问题是:我认为我必须伪造数据库层,但这不是让我自己创建一个“简单数据库”吗?或者:我如何保持它的简单,而不只是为了单元测试而重建Sql Server:)

在这个问题的最后,我将解释一下我刚刚开始的项目的情况,我想知道这是否是一条路要走

米歇尔

我在这个客户端看到的当前情况是,testdata包含在XML文件中,并且有一个“伪”数据库层将所有XML文件连接在一起。 对于真实的数据库,我们使用实体框架,这非常简单。 现在,在“假”层,我创建了各种类型的类来加载、保存、持久化数据。 这听起来很奇怪,在假层中有这么多的工作,而在真实层中却很少

我希望这一切都有意义:)

编辑:
所以我知道我必须为我的单元测试创建一个单独的数据库层,但是我如何实现它呢?

我在单元测试中使用的是假的DB

我一直在内存中使用Sqlite进行单元测试,它非常有用

为什么不使用模拟框架(比如moq或rhino模拟)?如果通过接口访问数据,则可以模拟该接口,并在每次测试中指定要返回的内容。另一种方法是使用单独的环境进行测试,使用“真实”数据库,在为生产环境编写代码之前进行测试。

为数据访问层定义一个接口,并(至少)有两种实现:

  • 真正的数据库提供程序,它将依次在SQL数据库上运行查询,等等
  • 内存中的测试提供程序,可以在每个单元测试中预先填充测试数据
这样做的好处是,使用数据提供者的模块不需要知道数据库是真实的还是测试的,因此将测试更多的真实代码。测试数据库可以是简单的(如简单的对象集合)或复杂的(带有索引的自定义结构)。它也可以是一个模拟的实现,它将断言它作为测试的一部分被适当地调用

此外,如果您需要支持另一种数据存储方法(或不同的SQL数据库),则只需编写另一个符合该接口的实现,并且可以确信调用代码都不需要重新编写

如果你从一开始就计划好(或接近开始),那么这种方法是最简单的,所以我不确定应用于你的情况会有多容易

它看起来像什么 如果您只是按id加载和保存对象,那么您可以有一个接口和实现,如(在Java风格的伪代码中;我对asp.net不太了解):

如果需要运行更多其他查询(例如基于更复杂条件的批选择),可以向接口中添加执行此操作的方法


对于复杂的更新也是如此。事务支持对于真正的数据库实现是可能的。我不确定构建一个能够提供适当事务支持的内存数据库有多容易。要测试它,您需要“打开”多个到同一数据集的“连接”,并且在提交事务时只对该共享数据集应用更新。

uhhh。。。。。。如果将所有测试数据存储在XML文件中。您刚刚将一个数据库更改为另一个数据库。这不是内存中的数据库。在PHP中,您可以使用如下内容

class MemoryProductDB {

    private $products;

    function MemoryProductDB() {
        $this->products = array();
    }

    public function find($index) {
        return $this->products[$index];
    }

    public function save($product) {
        $this->products[$product['index']] = $product;
    }
}
您注意到我的所有数据都存储在内存数组中,并从内存数组中检索。这是一个简单的内存数据库

IMHO,如果您使用XML存储测试数据,那么您实际上没有有效地断开依赖关系与模型和数据库的连接。无论您的业务规则有多复杂,当它们触及数据库时,它们真正做的只是CRUD(创建、检索、更新和删除)功能

如果您在模型中处理的是数据库中的多个对象,那么可能需要将所有这些对象组合成一个对象,并让模型使用该对象。例如,由产品组成的
订单。不要先检索产品,然后再保存产品。检索订单,然后保存订单,并让您的模型处理订单。模特不应该对产品有任何了解

这称为抽象的粒度

[编辑] 评论中有一个很好的问题。当使用内存中的数据库进行测试时,我们不关心select在数据库中的工作方式。首先,控制器必须在数据库上具有功能,以统计可用于分页访问的可能记录数。IMDb(内存数据库)应该只发送一个数字。管制员永远不应该关心这个数字是多少。与实际记录相同。希望您的控制器所做的只是显示从IMDb返回的内容

[编辑] 您不应该使用活动模型和imdb对控制器进行单元测试。imdb的设置代码将有很大的摩擦。相反,当对控制器进行单元测试时,您需要对模拟、存根、伪模型进行单元测试。imdb的最佳使用是在集成测试期间或在单元测试模型时。imdb不是假的吗

我的设想是:

  • 在我的客户机中,我使用一个表插件。服务器端处理
  • 客户端获取请求
    class MemoryProductDB {
    
        private $products;
    
        function MemoryProductDB() {
            $this->products = array();
        }
    
        public function find($index) {
            return $this->products[$index];
        }
    
        public function save($product) {
            $this->products[$product['index']] = $product;
        }
    }
    
    public function testSkuTable() {
        $skus = array(
                array('id' => '1', 'data' => 'data1'),
                array('id' => '2', 'data' => 'data2'),
                array('id' => '3', 'data' => 'data3'));
    
        $names = array(
                'id',
                'data');
        $start_row = $this->parameters['start_row'];
        $num_rows = $this->parameters['num_rows'];
        $sort_col = $this->parameters['sort_col'];
        $search = $this->parameters['search'];
        $requestSequence = $this->parameters['request_sequence'];
        $direction = $this->parameters['dir'];
        $filterTotals = 1;
        $totalRecords = 1;
    
        $this->gateway->expects($this->once())
                ->method('names')
                ->with($this->vendor)
                ->will($this->returnValue($names));
    
        $this->gateway->expects($this->once())
                ->method('skus')
                ->with($this->vendor, $names, $start_row, $num_rows, $sort_col, $search, $direction)
                ->will($this->returnValue($skus));
    
        $this->gateway->expects($this->once())
                ->method('filterTotals')
                ->will($this->returnValue($filterTotals));
    
        $this->gateway->expects($this->once())
                ->method('totalRecords')
                ->with($this->vendor)
                ->will($this->returnValue($totalRecords));
    
        $expectJson = '{"sEcho": '.$requestSequence.', "iTotalRecords": '.$totalRecords.', "iTotalDisplayRecords": '.$filterTotals.', "aaData": [ ["1","data1"],["2","data2"],["3","data3"]] }';
        $actualJson = $this->skusModel->skuTable($this->vendor, $this->parameters);
    
        $this->assertEquals($expectJson, $actualJson);
    }
    
    public function skuTable($vendor, $parameterList) {
        $startRow = $parameterList['start_row'];
        $numRows = $parameterList['num_rows'];
        $sortCols = $parameterList['sort_col'];
        $search = $parameterList['search'];
        if($search == null) {
            $search = "";
        }
        $requestSequence = $parameterList['request_sequence'];
        $direction = $parameterList['dir'];
    
        $names = $this->propertyNames($vendor);
        $skus = $this->skusList($vendor, $names, $startRow, $numRows, $sortCols, $search, $direction);
        $filterTotals = $this->filterTotals($vendor, $names, $startRow, $numRows, $sortCols, $search, $direction);
        $totalRecords = $this->totalRecords($vendor);
    
        return $this->buildJson($requestSequence, $totalRecords, $filterTotals, $skus, $names);
    }
    
    public function skusList($vendor, $names, $start_row, $num_rows, $sort_col, $search, $direction) {
        return $this->skusGateway->skus($vendor, $names, $start_row, $num_rows, $sort_col, $search, $direction);
    }