В вашем сценарии вам не нужно подделывать никакие временные таблицы, просто подделайте таблицу, на которую ссылается Marketing.API_StoredPro c, и заполните ее значениями, которые вы ожидаете получить, а некоторые - нет. , Добавьте то, что вы ожидаете увидеть в #expected таблице, вызовите Marketing.API_StoredProc
, дампируя результаты в #actual таблицу, и сравните результаты с tSQLt.AssertEqualsTable.
Хорошей отправной точкой может быть рассмотрение того, как tSQLT.FakeTable
работает и в реальных условиях использования.
Как вы знаете, каждый модульный тест выполняется в рамках своей собственной транзакции, запущенной и откатанной инфраструктурой tSQLT. Когда вы вызываете tSQLt.FakeTable в модульном тесте, он временно переименовывает указанную таблицу, а затем создает точно названный факсимильный аппарат этой таблицы. Временная копия допускает NULL в каждом столбце, не имеет первичных или внешних ключей, идентификатора столбца, проверки, ограничений по умолчанию или уникальных ограничений (хотя некоторые из них могут быть включены в факсимильную таблицу в зависимости от параметров, передаваемых в tSQLt.FakeTable). Во время тестовой транзакции любой объект, который ссылается на таблицу имен, будет использовать поддельную, а не реальную таблицу. В конце теста tSQLt откатывает транзакцию, поддельная таблица удаляется, а исходная таблица возвращается в прежнее состояние (все это происходит автоматически). Вы можете спросить, в чем смысл этого?
Представьте, что у вас есть таблица [OrderDetail], в которой столбцы включают OrderId и ProductId в качестве первичного ключа, столбец OrderStatusId плюс несколько других столбцов NOT NULL. DDL для этой таблицы может выглядеть примерно так:
CREATE TABLE [dbo].[OrderDetail]
(
OrderDetailId int IDENTITY(1,1) NOT NULL
, OrderId int NOT NULL
, ProductId int NOT NULL
, OrderStatusId int NOT NULL
, Quantity int NOT NULL
, CostPrice decimal(18,4) NOT NULL
, Discount decimal(6,4) NOT NULL
, DeliveryPreferenceId int NOT NULL
, PromisedDeliveryDate datetime NOT NULL
, DespatchDate datetime NULL
, ActualDeliveryDate datetime NULL
, DeliveryDelayReason varchar(500) NOT NULL
/* ... other NULL and NOT NULL columns */
, CONSTRAINT PK_OrderDetail PRIMARY KEY CLUSTERED (OrderId, ProductId)
, CONSTRAINT AK_OrderDetail_AutoIncrementingId UNIQUE NONCLUSTERED (OrderDetailId)
, CONSTRAINT FK_OrderDetail_Order FOREIGN KEY (OrderId) REFERENCES [dbo].[Orders] (OrderId)
, CONSTRAINT FK_OrderDetail_Product FOREIGN KEY (ProductId) REFERENCES [dbo].[Product] (ProductId)
, CONSTRAINT FK_OrderDetail_OrderStatus FOREIGN KEY (OrderStatusId) REFERENCES [dbo].[OrderStatus] (OrderStatusId)
, CONSTRAINT FK_OrderDetail_DeliveryPreference FOREIGN KEY (DeliveryPreferenceId) REFERENCES [dbo].[DeliveryPreference] (DeliveryPreferenceId)
);
Как видите, эта таблица имеет зависимости внешнего ключа от таблиц Orders, Product, DeliveryPreference и OrderStatus. Продукт, в свою очередь, может иметь внешние ключи, которые, среди прочего, ссылаются на ProductType, BrandCategory, Supplier. Таблица Orders содержит ссылки на внешние ключи для Customer, Address и SalesPerson. Все таблицы в этой цепочке имеют многочисленные столбцы, определенные как NOT NULL и / или ограниченные CHECK и другими ограничениями. Некоторые из этих таблиц имеют больше внешних ключей.
Теперь представьте, что вы хотите написать хранимую процедуру (OrderDetailStatusUpdate), задачей которой является обновление статуса заказа для одной строки в таблице OrderDetail. Он имеет три входных параметра @OrderId, @ProductId и @OrderStatusId. Подумайте, что вам нужно сделать, чтобы настроить тест для этой процедуры. Вам необходимо добавить как минимум две строки в таблицу OrderDetail, включая все столбцы NOT NULL. Вам также необходимо добавить родительские записи во все таблицы, на которые ссылаются FK, а также во все таблицы выше этой иерархии, чтобы гарантировать, что все ваши вставки соответствуют всем допускаемым обнуляемостью и другим ограничениям для этих таблиц. По моим подсчетам, это как минимум 11 таблиц, которые нужно заполнить, все для одного простого теста. И даже если вы прикусите пулю и выполните все эти настройки, в какой-то момент в будущем кто-то может (вероятно, будет) прийти и добавить новый столбец NOT NULL в одну из этих таблиц или изменить ограничение, которое вызовет ваш тест провал - и этот сбой на самом деле не имеет ничего общего с вашим тестом или хранимой процедурой, которую вы тестируете. Один из базовых c принципов разработки, основанной на тестах, заключается в том, что тест должен иметь только причину неудачи, я считаю десятки.
tSQLT.FakeTable на помощь.
Что такое минимум, который вам действительно нужно сделать, чтобы настроить тест для этой процедуры? Вам нужно две строки в таблице OrderDetail (одна обновляется, другая нет), и единственные столбцы, которые вам «нужно» учитывать, это OrderId и ProductId (идентификационный ключ) плюс OrderStatusId - обновляемый столбец. Остальные столбцы, хотя и важны в общем проекте, не имеют отношения к тестируемому объекту. В своем тесте для OrderDetailStatusUpdate вы должны выполнить следующие шаги:
- Вызовите tSQLt.FakeTable 'dbo.OrderDetail'
- Создайте таблицу #expected (со столбцами OrderId, ProductId и OrderStatusId) и заполните ее двумя строками, которые, как вы ожидаете, закончатся (одна будет иметь ожидаемый OrderStatusId, а другая может быть NULL)
- Добавить две строки в теперь смоделированной таблице OrderDetail (только для OrderId и ProductId)
- Вызовите тестируемую процедуру OrderDetailStatusUpdate, передавая OrderID и ProductID для одной из вставленных строк плюс идентификатор OrderStatusId, на который вы меняете.
- Используйте tSQLt.AssertEqualsTable, чтобы сравнить ожидаемую таблицу с таблицей OrderDetail. Это утверждение будет сравнивать только столбцы в таблице #expected, остальные столбцы в OrderDetail будут проигнорированы
Создание этого теста действительно быстрое, и единственная причина, по которой он может потерпеть неудачу, заключается в том, что что-то уместное чтобы тестируемый код изменился в базовой схеме. Изменения в любых других столбцах таблицы OrderDetail или любой из таблиц parent / grand-parent не приведут к сбою этого теста.
Поэтому причина использования tSQLt.FakeTable (или любого другого типа фиктивного объекта) обеспечить действительно надежную изоляцию теста и просто подготовить данные теста.