Как протестировать систему безопасности?
1. Выдать пользователю роль;
2. Зайти под ним в систему;
3. Зайти в проверяемый модуль;
4. Профит! В смысле, сам тест
Первые три пункта весьма удручают при ручном тестировании. А еще сильнее – при автоматизированном. Ведь мы делаем автотесты, чтобы облегчить свою жизнь, создать возможность прогнать большее число тестов за меньшее время…
Поэтому первый пункт желательно выкинуть из GUI, а настраивать прямо через базу. Ведь он может много времени занять: зайти под мега-супер-админом, найти в системе нужного пользователя, удалить все его старые роли, выдать только нужную… А все вокруг лагает, лагает…
Проще ведь через базу, да? Найти нужную табличку «пользователь - его роли», удалить оттуда все строки, относящие к данному пользователю (вы можете создавать его в том же автотесте, можете использовать уже существующего, если с созданием новой учетки есть некоторые проблемы/затраты во времени (подтверждение админом), тут уже вам решать, откуда id пользователя тащить). И добавить одну или несколько своих.
Попробуем сделать это на примере нашего приложения, достающего из базы всех авторов, а также их книги.
В студии у нас уже есть в этом solution-е 2 проекта: «Books.Model» и «Books.Web». Добавляем новый проект класса «Library» - «Books.Tests». В реальной жизни нам понадобится только наша модель и сами тесты, «веб»-часть мы просто выкидываем.
Но раз уж она есть, будем контролировать корректность выполнения теста. Ведь по сути у нас задача написать не сам тест, а «то, что будет сделано ДО выполнения тестов». Значит, никакие проверки внутри не нужны. Проверим руками, запустив приложение. Если нет веб-части, можно посмотреть и в SQL Server Managеment Studio.
Итак, создали тесты. Добавляем сразу конфигурационный файл в проект:
В нем указываем строку соединения.
<connectionStrings>
<add name="BooksDb" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=Books;User ID=ap;Password="/>
</connectionStrings>
Теперь запишем сам тест:
using Books.Model;
using NUnit.Framework;
namespace Books.Tests
{
[TestFixture]
public class Test
{
public int idAuthor;
public int idBook;
[Test]
public void ЗадатьАвтораУжастика()
{
idAuthor = 2;
idBook = 8;
using (var db = new Books.Model.BooksModelDataContext(ConfigurationManager.ConnectionStrings["BooksDb"].ConnectionString))
{
using (var tran = new TransactionScope())
{
var ordDetailQuery =
from a in db.BookAuthorships
where a.authorId == idAuthor
select a;
db.BookAuthorships.DeleteAllOnSubmit(ordDetailQuery);
var ba = new BookAuthorship();
ba.authorId = idAuthor;
ba.bookId = idBook;
db.BookAuthorships.InsertOnSubmit(ba);
db.SubmitChanges();
tran.Complete();
}
}
}
}
}
using Books.Model; - мы будем работать с моделью, подключаем ее в references на закладке проектов, подключаем ее namespace в наш тест.
using NUnit.Framework; - с его помощью мы определяем наш набор тестов.
[TestFixture] – атрибут NUnit.Framework, указывает на то, что ниже идет набор тестов, помеченных атбитом [Test]. В реальности этот наш «тест» будет не самим тестом, а заготовкой, то есть он будет лежать в базовом классе, помеченный атрибутом [TestFixtureSetUp].
idAuthor = 2;
idBook = 8;
В нашем тесте мы хотим конкретному автору («Ольга К») сопоставить конкретную книгу. Лезем в базу, узнаем их id. Задаем явно. Можно тащить из какого-нибудь конфига. Если потребуется.
Далее стандартно – чтобы обратиться к базе, нужно выполнить операцию. Операция должна быть обернута в транзакцию. Для открытия транзакции необходимо открыть соединение.
Делаем выборку из базы всех строк с автором «Ольга К»
var ordDetailQuery =
from a in db.BookAuthorships
where a.authorId == idAuthor
select a;
Удаляем их:
db.BookAuthorships.DeleteAllOnSubmit(ordDetailQuery);
Создаем entity с параметрами, которые мы хотим видеть в базе в итоге:
var ba = new BookAuthorship();
ba.authorId = idAuthor;
ba.bookId = idBook;
Помещаем его в базу:
db.BookAuthorships.InsertOnSubmit(ba);
Сохраняем изменения в базе, закрываем транзакцию.
F5 – стартуем приложение. У нашей «подопытной» три книги:
Прогоняем тест.
Снова стартуем приложение:
Вуаля J
>Проще ведь через базу, да?
ОтветитьУдалитьНаверное, проще, но ведь сами же лезете грязными руками в БД. Как вы потом будете доказывать, что проблема в тестируемом приложении, а не в том, что ваш автотест криво проадейтил данные в БД? Будете руками воспроизводить, на этот раз по-честному?
И - как убедитесь, что при работе через UI все настройки выставляются правильно? Отдельно это тестировать?
Да и при изменении БД придется автотествы переписывать.
Лучше бы как средство ускорения в таком случае использовать API. Если его нет - то это уже другой вопрос и начало другой темы )
Да, я проверю ручками, если тест упадет. И сделаю это в любом случае. Если же протестировать апдейт, то с ним потом проблем не будет.
ОтветитьУдалитьИ да, назначение роли можно проверить отдельно.
Можно сгруппировать тесты по-разному.
Быстрые тесты все обновят через базу и проверят то, что все роли работают корректно, у них хотя бы не отваливается ничего.
Более медленные проверят уже назначение роли в интерфейсе. Хотя, по сути, я могу попросить программиста дать мне код их апдейта, который выполняется при сохранении роли через GUI. Тогда, если он полетит - значит, криво был написан код программы.
Давайте остановимся в этой теме на конкретном вопросе :)