Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Тестирование на основе сетей Петри

Тестирование на основе сетей Петри

A talk about automated exploratory testing based on Petri net models for HeisenBug Piter 2018 (https://2018.heisenbug-piter.ru/talks/2018/spb/6feubdtqqwqocya2w4cwq2/). The recording of the talk is available on YouTube (https://www.youtube.com/watch?v=TeKHZw61pb8).

Alex Rodionov

May 17, 2018
Tweet

More Decks by Alex Rodionov

Other Decks in Programming

Transcript

  1. ДЛЯ КОГО? 1.Для тех, у кого много тестов и багов.

    2.Для тех, кто только планирует автоматизированное тестирование. 11
  2. 1. Недостаточность обычных тестов 2. Тестирование на основе моделей 3.

    Сети Петри 4. Тестирование на основе сетей Петри
  3. 1. Недостаточность обычных тестов 2. Тестирование на основе моделей 3.

    Сети Петри 4. Тестирование на основе сетей Петри
  4. 23 class User < ApplicationRecord end it 'destroys user’ do

    user = User.create! user.destroy expect(User.count).to eq(0) end
  5. 24 arrange act assert class User < ApplicationRecord end it

    'destroys user’ do user = User.create! user.destroy expect(User.count).to eq(0) end
  6. 25 class User < ApplicationRecord end it 'destroys user’ do

    user = User.create! user.destroy expect(User.count).to eq(0) end
  7. 26 class User < ApplicationRecord has_many :notes end class Note

    < ApplicationRecord belongs_to :user end it 'destroys user’ do user = User.create! user.destroy expect(User.count).to eq(0) end
  8. 27 class User < ApplicationRecord has_many :notes end class Note

    < ApplicationRecord belongs_to :user end it 'destroys user with a note’ do user = User.create!(note: Note.create!) user.destroy expect(User.count).to eq(0) end
  9. 28 class User < ApplicationRecord has_many :notes end class Note

    < ApplicationRecord belongs_to :user end it 'destroys user with a note’ do user = User.create!(note: Note.create!) user.destroy expect(User.count).to eq(0) end
  10. 29 class User < ApplicationRecord has_many :notes end class Note

    < ApplicationRecord belongs_to :user end ActiveRecord ::InvalidForeignKey: PG ::ForeignKeyViolation: ERROR: update or delete on table "users" violates foreign key constraint “fk_rails_83d9817008" on table "notes" DETAIL: Key (id)=(1) is still referenced from table “notes".
  11. 30 class User < ApplicationRecord has_many :notes, dependent: :destroy end

    class Note < ApplicationRecord belongs_to :user end it 'destroys user with a note’ do user = User.create!(note: Note.create!) user.destroy expect(User.count).to eq(0) end
  12. 31 class User < ApplicationRecord has_many :notes, dependent: :destroy end

    class Note < ApplicationRecord belongs_to :user end it 'destroys user with a note’ do user = User.create!(note: Note.create!) user.destroy expect(User.count).to eq(0) end
  13. 1. Недостаточность обычных тестов 2. Тестирование на основе моделей 3.

    Сети Петри 4. Тестирование на основе сетей Петри
  14. 51 @GraphWalker(value = "random(edge_coverage(100))", start = "v_NotesListView") public class NotesListTest

    { @Override public void e_GoToNewNoteView() { driver.pressKeyCode(AndroidKeyCode.KEYCODE_MENU); driver.findElementByClassName("android.widget.TextView").click(); } }
  15. 52 @GraphWalker(value = "random(edge_coverage(100))", start = "v_NotesListView") public class NotesListTest

    { @Override public void e_Discard() { driver.pressKeyCode(AndroidKeyCode.KEYCODE_MENU); driver.findElementByClassName("android.widget.TextView").click(); } }
  16. 54 @GraphWalker(value = "random(edge_coverage(100))", start = "v_NotesListView") public class NotesListTest

    { @Override public void e_Create() { String noteName = "test+" + new Random().nextInt(); } }
  17. 55 @GraphWalker(value = "random(edge_coverage(100))", start = "v_NotesListView") public class NotesListTest

    { @Override public void e_Create() { String noteName = "test+" + new Random().nextInt(); driver.findElement(By.xpath(" //android.widget.EditText[1]")) .sendKeys(noteName); } }
  18. 56 @GraphWalker(value = "random(edge_coverage(100))", start = "v_NotesListView") public class NotesListTest

    { @Override public void e_Create() { String noteName = "test+" + new Random().nextInt(); driver.findElement(By.xpath(" //android.widget.EditText[1]")) .sendKeys(noteName); driver.hideKeyboard(); driver.pressKeyCode(AndroidKeyCode.KEYCODE_BACK); } }
  19. 57 @GraphWalker(value = "random(edge_coverage(100))", start = "v_NotesListView") public class NotesListTest

    { @Override public void e_Create() { String noteName = "test+" + new Random().nextInt(); driver.findElement(By.xpath(" //android.widget.EditText[1]")) .sendKeys(noteName); driver.hideKeyboard(); driver.pressKeyCode(AndroidKeyCode.KEYCODE_BACK); expectedNumberOfNotes ++; } }
  20. 59 @GraphWalker(value = "random(edge_coverage(100))", start = "v_NotesListView") public class NotesListTest

    { @Override public void v_NotesListView() { WebElement notesList = driver.findElementByClassName("android.widget.TextView"); assertTrue(notesList.getText().equals("Note pad”)); } }
  21. 60 @GraphWalker(value = "random(edge_coverage(100))", start = "v_NotesListView") public class NotesListTest

    { @Override public void v_NotesListView() { WebElement notesList = driver.findElementByClassName("android.widget.TextView"); assertTrue(notesList.getText().equals("Note pad”)); List<WebElement> notesInList = driver.findElement(By.className("android.widget.ListView")) .findElements(By.className("android.widget.TextView")); int actualNumberOfNotes = notesInList.size(); assertEquals(expectedNumberOfNotes, actualNumberOfNotes); } }
  22. 62 @GraphWalker(value = "random(edge_coverage(100))", start = "v_NotesListView") public class NotesListTest

    { @Override public void v_NewNoteView() { WebElement notesEditor = driver.findElementByClassName("android.widget.EditText"); Assert.assertTrue(notesEditor.isDisplayed()); } }
  23. 64 $ mvn graphwalker:test [INFO] Tests: [INFO] NotesListTest(RandomPath, VertexCoverage, 100)

    Before element v_NotesListView After element v_NotesListView
  24. 65 $ mvn graphwalker:test [INFO] Tests: [INFO] NotesListTest(RandomPath, VertexCoverage, 100)

    Before element v_NotesListView After element v_NotesListView Before element e_GoToNewNoteView After element e_GoToNewNoteView
  25. 66 $ mvn graphwalker:test [INFO] Tests: [INFO] NotesListTest(RandomPath, VertexCoverage, 100)

    Before element v_NotesListView After element v_NotesListView Before element e_GoToNewNoteView After element e_GoToNewNoteView Before element v_NewNoteView After element v_NewNoteView
  26. 67 $ mvn graphwalker:test [INFO] Tests: [INFO] NotesListTest(RandomPath, VertexCoverage, 100)

    Before element v_NotesListView After element v_NotesListView Before element e_GoToNewNoteView After element e_GoToNewNoteView Before element v_NewNoteView After element v_NewNoteView Before element e_Create After element e_Create
  27. 68 $ mvn graphwalker:test [INFO] Tests: [INFO] NotesListTest(RandomPath, VertexCoverage, 100)

    Before element v_NotesListView After element v_NotesListView Before element e_GoToNewNoteView After element e_GoToNewNoteView Before element v_NewNoteView After element v_NewNoteView Before element e_Create After element e_Create Before element v_NotesListView After element v_NotesListView
  28. 69 $ mvn graphwalker:test [INFO] Tests: [INFO] NotesListTest(RandomPath, VertexCoverage, 100)

    Before element v_NotesListView After element v_NotesListView Before element e_GoToNewNoteView After element e_GoToNewNoteView Before element v_NewNoteView After element v_NewNoteView Before element e_Create After element e_Create Before element v_NotesListView After element v_NotesListView Before element e_GoToNewNoteView After element e_GoToNewNoteView
  29. 70 $ mvn graphwalker:test [INFO] Tests: [INFO] NotesListTest(RandomPath, VertexCoverage, 100)

    Before element v_NotesListView After element v_NotesListView Before element e_GoToNewNoteView After element e_GoToNewNoteView Before element v_NewNoteView After element v_NewNoteView Before element e_Create After element e_Create Before element v_NotesListView After element v_NotesListView Before element e_GoToNewNoteView After element e_GoToNewNoteView Before element v_NewNoteView After element v_NewNoteView
  30. 71 $ mvn graphwalker:test [INFO] Tests: [INFO] NotesListTest(RandomPath, VertexCoverage, 100)

    Before element v_NotesListView After element v_NotesListView Before element e_GoToNewNoteView After element e_GoToNewNoteView Before element v_NewNoteView After element v_NewNoteView Before element e_Create After element e_Create Before element v_NotesListView After element v_NotesListView Before element e_GoToNewNoteView After element e_GoToNewNoteView Before element v_NewNoteView After element v_NewNoteView Before element e_Discard After element e_Discard
  31. 72 $ mvn graphwalker:test [INFO] Tests: [INFO] NotesListTest(RandomPath, VertexCoverage, 100)

    Before element v_NotesListView After element v_NotesListView Before element e_GoToNewNoteView After element e_GoToNewNoteView Before element v_NewNoteView After element v_NewNoteView Before element e_Create After element e_Create Before element v_NotesListView After element v_NotesListView Before element e_GoToNewNoteView After element e_GoToNewNoteView Before element v_NewNoteView After element v_NewNoteView Before element e_Discard After element e_Discard Before element v_NotesListView After element v_NotesListView
  32. 1. Недостаточность обычных тестов 2. Тестирование на основе моделей 3.

    Сети Петри 4. Тестирование на основе сетей Петри
  33. СЕТЬ ПЕТРИ 85 позиции (places) хранят метки дуги связывают позиции

    и переходы переходы (transitions) перемещают метки not created Create User created
  34. СЕТЬ ПЕТРИ 88 срабатывание удаляет метку из not created и

    добавляет в created not created Create User created
  35. 90 1. Переходы могут быть связаны только с позициями (и

    наоборот) 2. Переход может сработать когда в каждой входной позиции есть по меньшей мере одна метка СЕТЬ ПЕТРИ
  36. 91 1. Переходы могут быть связаны только с позициями (и

    наоборот) 2. Переход может сработать когда в каждой входной позиции есть по меньшей мере одна метка 3. Срабатывание перехода забирает по одной метке из каждой входной позиции и добавляет по одной метке в каждую выходную позицию СЕТЬ ПЕТРИ
  37. СЕТЬ ПЕТРИ 93 not created Create User created ip allowed

    not created Create User created ip allowed
  38. СЕТЬ ПЕТРИ 95 pending review not created Create User created

    pending review not created Create User created
  39. СЕТЬ ПЕТРИ 103 user not created user created note created

    Create User Destroy User Create Note Destroy Note
  40. СЕТЬ ПЕТРИ 104 user not created user created note created

    Create User Destroy User Create Note Destroy Note
  41. СЕТЬ ПЕТРИ 105 user not created user created note created

    Create User Destroy User Create Note Destroy Note
  42. СЕТЬ ПЕТРИ 106 user not created user created note created

    Create User Destroy User Create Note Destroy Note
  43. СЕТЬ ПЕТРИ 108 user not created user created note created

    Create User Destroy User Create Note Destroy Note post created
  44. СЕТЬ ПЕТРИ 109 user not created user created note created

    Create User Destroy User Create Note Destroy Note post created Create Post
  45. СЕТЬ ПЕТРИ 110 user not created user created note created

    Create User Destroy User Create Note Destroy Note post created Create Post Destroy Post
  46. СЕТЬ ПЕТРИ 112 user not created user created note created

    Create User Destroy User Create Note Destroy Note post created Create Post Destroy Post video created
  47. СЕТЬ ПЕТРИ 113 user not created user created note created

    Create User Destroy User Create Note Destroy Note post created Create Post Destroy Post Create Video video created
  48. СЕТЬ ПЕТРИ 114 user not created user created note created

    Create User Destroy User Create Note Destroy Note post created Create Post Destroy Post Create Video Destroy Video video created
  49. 1. Недостаточность обычных тестов 2. Тестирование на основе моделей 3.

    Сети Петри 4. Тестирование на основе сетей Петри
  50. СОЗДАНИЕ МОДЕЛИ 120 { "places": [ { "guid": "e57c0830-148f-11e8-bb7f-adf9986e1043", "identifier":

    "user created" } ], "transitions": [ { "guid": “df65a6e0-148f-11e8-bb7f-adf9986e1043" "identifier": "Create User", } ], "arcs": [ { "from_guid": "e57c0830-148f-11e8-bb7f-adf9986e1043", "to_guid": “df65a6e0-148f-11e8-bb7f-adf9986e1043" } ] }
  51. ЗАГРУЗКА СЕТИ 123 class Node def input_arcs # ... end

    def output_arcs # ... end end class Place < Node end
  52. ЗАГРУЗКА СЕТИ 124 class Node def input_arcs # ... end

    def output_arcs # ... end end class Place < Node end class Transition < Node end
  53. ЗАГРУЗКА СЕТИ 125 class Node def input_arcs # ... end

    def output_arcs # ... end end class Place < Node end class Transition < Node end class Arc def from # ... end def to # ... end end
  54. ЗАГРУЗКА СЕТИ 126 class Runner def enabled?(transition) # ... end

    def fire(transition) # ... end def marking # ... end end
  55. СВЯЗЬ СЕТИ С ТЕСТОВЫМ КОДОМ 128 user not created user

    created note created Create User Destroy User Create Note Destroy Note
  56. 129 user not created user created note created Create User

    Destroy User Create Note Destroy Note class UserNoteNet < Rhizome ::Net end
  57. 130 user not created user created note created Create User

    Destroy User Create Note Destroy Note class UserNoteNet < Rhizome ::Net runner { Runner.new('user-note.bpf', marking: ['user not created']) } end
  58. 131 class UserNoteNet < Rhizome ::Net runner { Runner.new('user-note.bpf', marking:

    ['user not created']) } transition('Create User') { @user = User.create! } transition('Destroy User') { @user.destroy } end user not created user created note created Create User Destroy User Create Note Destroy Note
  59. 132 class UserNoteNet < Rhizome ::Net runner { Runner.new('user-note.bpf', marking:

    ['user not created']) } transition('Create User') { @user = User.create! } transition('Destroy User') { @user.destroy } transition('Create Note') { @note = Note.create!(user: @user) } transition('Destroy Note') { @note.destroy } end user not created user created note created Create User Destroy User Create Note Destroy Note
  60. 133 class UserNoteNet < Rhizome ::Net runner { Runner.new('user-note.bpf', marking:

    ['user not created']) } transition('Create User') { @user = User.create! } transition('Destroy User') { @user.destroy } transition('Create Note') { @note = Note.create!(user: @user) } transition('Destroy Note') { @note.destroy } place('user not created') do empty { expect(User.count).to be > 0 } filled { expect(User.count).to eq(0) } end end user not created user created note created Create User Destroy User Create Note Destroy Note
  61. 134 class UserNoteNet < Rhizome ::Net runner { Runner.new('user-note.bpf', marking:

    ['user not created']) } transition('Create User') { @user = User.create! } transition('Destroy User') { @user.destroy } transition('Create Note') { @note = Note.create!(user: @user) } transition('Destroy Note') { @note.destroy } place('user not created') do empty { expect(User.count).to be > 0 } filled { expect(User.count).to eq(0) } end place('user created') do empty { expect(User.count).to eq(0) } filled { expect(User.count).to be > 0 } end end user not created user created note created Create User Destroy User Create Note Destroy Note
  62. class UserNoteNet < Rhizome ::Net runner { Runner.new('user-note.bpf', marking: ['user

    not created']) } transition('Create User') { @user = User.create! } transition('Destroy User') { @user.destroy } transition('Create Note') { @note = Note.create!(user: @user) } transition('Destroy Note') { @note.destroy } place('user not created') do empty { expect(User.count).to be > 0 } filled { expect(User.count).to eq(0) } end place('user created') do empty { expect(User.count).to eq(0) } filled { expect(User.count).to be > 0 } end place('note created') do empty { expect(Note.count).to eq(0) } filled { expect(Note.count).to be > 0 } end end user not created user created note created Create User Destroy User Create Note Destroy Note 135
  63. ОБХОД СЕТИ 1. Даем каждому переходу одинаковую вероятность (4 перехода

    = 0,25 каждому) 2. Генерируем случайное число - порог вероятности выбора перехода 137
  64. ОБХОД СЕТИ 1. Даем каждому переходу одинаковую вероятность (4 перехода

    = 0,25 каждому) 2. Генерируем случайное число - порог вероятности выбора перехода 3. Выбираем первый переход с подходящей под порог вероятностью, который может сработать 138
  65. ОБХОД СЕТИ 1. Даем каждому переходу одинаковую вероятность (4 перехода

    = 0,25 каждому) 2. Генерируем случайное число - порог вероятности выбора перехода 3. Выбираем первый переход с подходящей под порог вероятностью, который может сработать 4. Срабатываем переход 139
  66. ОБХОД СЕТИ 1. Даем каждому переходу одинаковую вероятность (4 перехода

    = 0,25 каждому) 2. Генерируем случайное число - порог вероятности выбора перехода 3. Выбираем первый переход с подходящей под порог вероятностью, который может сработать 4. Срабатываем переход 5. Проверяем пустые и заполненные позиции 140
  67. ОБХОД СЕТИ 1. Даем каждому переходу одинаковую вероятность (4 перехода

    = 0,25 каждому) 2. Генерируем случайное число - порог вероятности выбора перехода 3. Выбираем первый переход с подходящей под порог вероятностью, который может сработать 4. Срабатываем переход 5. Проверяем пустые и заполненные позиции 6. Уменьшаем вероятность сработанного перехода в 2 раза 141
  68. ОБХОД СЕТИ 1. Даем каждому переходу одинаковую вероятность (4 перехода

    = 0,25 каждому) 2. Генерируем случайное число - порог вероятности выбора перехода 3. Выбираем первый переход с подходящей под порог вероятностью, который может сработать 4. Срабатываем переход 5. Проверяем пустые и заполненные позиции 6. Уменьшаем вероятность сработанного перехода в 2 раза 7. Если все переходы сработали хотя бы раз, останавливаемся. Если нет, повторяем с пункта 2 142
  69. 144 $ bin/rhizome Traversing user_note net: Initial marking: user not

    created Executing Create User New marking: user created Transitions left: Destroy User, Create Note, Destroy Note
  70. 145 $ bin/rhizome Traversing user_note net: Initial marking: user not

    created Executing Create User New marking: user created Transitions left: Destroy User, Create Note, Destroy Note Executing Create Note New marking: user created, note created Transitions left: Destroy User, Destroy Note
  71. 146 $ bin/rhizome Traversing user_note net: Initial marking: user not

    created Executing Create User New marking: user created Transitions left: Destroy User, Create Note, Destroy Note Executing Create Note New marking: user created, note created Transitions left: Destroy User, Destroy Note Executing Destroy Note New marking: user created Transitions left: Destroy User
  72. 147 $ bin/rhizome Traversing user_note net: Initial marking: user not

    created Executing Create User New marking: user created Transitions left: Destroy User, Create Note, Destroy Note Executing Create Note New marking: user created, note created Transitions left: Destroy User, Destroy Note Executing Destroy Note New marking: user created Transitions left: Destroy User Executing Destroy User New marking: user not created Finished traversing user_note net.
  73. 149 $ bin/rhizome Traversing user_note net: Initial marking: user not

    created Executing Create User New marking: user created Transitions left: Destroy User, Create Note, Destroy Note
  74. 150 $ bin/rhizome Traversing user_note net: Initial marking: user not

    created Executing Create User New marking: user created Transitions left: Destroy User, Create Note, Destroy Note Executing Destroy User New marking: user not created Transitions left: Create Note, Destroy Note
  75. 151 $ bin/rhizome Traversing user_note net: Initial marking: user not

    created Executing Create User New marking: user created Transitions left: Destroy User, Create Note, Destroy Note Executing Destroy User New marking: user not created Transitions left: Create Note, Destroy Note Executing Create User New marking: user created Transitions left: Create Note, Destroy Note
  76. 152 $ bin/rhizome Traversing user_note net: Initial marking: user not

    created Executing Create User New marking: user created Transitions left: Destroy User, Create Note, Destroy Note Executing Destroy User New marking: user not created Transitions left: Create Note, Destroy Note Executing Create User New marking: user created Transitions left: Create Note, Destroy Note Executing Create Note New marking: user created, note created Transitions left: Destroy Note
  77. 153 $ bin/rhizome Traversing user_note net: Initial marking: user not

    created Executing Create User New marking: user created Transitions left: Destroy User, Create Note, Destroy Note Executing Destroy User New marking: user not created Transitions left: Create Note, Destroy Note Executing Create User New marking: user created Transitions left: Create Note, Destroy Note Executing Create Note New marking: user created, note created Transitions left: Destroy Note Executing Destroy Note New marking: user created Finished traversing user_note net.
  78. 155 $ bin/rhizome Traversing user_note net: Initial marking: user not

    created Executing Create User New marking: user created Transitions left: Destroy User, Create Note, Destroy Note
  79. 156 $ bin/rhizome Traversing user_note net: Initial marking: user not

    created Executing Create User New marking: user created Transitions left: Destroy User, Create Note, Destroy Note Executing Create Note New marking: user created, note created Transitions left: Destroy User, Destroy Note
  80. 157 $ bin/rhizome Traversing user_note net: Initial marking: user not

    created Executing Create User New marking: user created Transitions left: Destroy User, Create Note, Destroy Note Executing Create Note New marking: user created, note created Transitions left: Destroy User, Destroy Note Executing Destroy User 
 ActiveRecord ::InvalidForeignKey: PG ::ForeignKeyViolation: ERROR: update or delete on table "users" violates foreign key constraint "fk_rails_83d9817008" on table "notes" DETAIL: Key (id)=(1) is still referenced from table “notes".
  81. RHIZOME 1. Воспроизводимость тестов с помощью seed 2. Параллелизация как

    у любого другого фреймворка 3. Фреймворк общего назначения (хоть с Selenium) 160
  82. ТЕСТИРОВАНИЕ НА ОСНОВЕ СЕТЕЙ ПЕТРИ 1. Тестовое покрытие увеличилось 2.

    Время выполнения тестов осталось прежним
 
 165
  83. ТЕСТИРОВАНИЕ НА ОСНОВЕ СЕТЕЙ ПЕТРИ 1. Тестовое покрытие увеличилось 2.

    Время выполнения тестов осталось прежним 3. Время на написание/поддержку тестов сократилось 166
  84. 168 user not created user created note created Create User

    Destroy User Create Note Destroy Note
  85. 169 user not created user created note created Create User

    Destroy User Create Note Destroy Note
  86. 170 user not created user created note created Create User

    Destroy User Create Note Destroy Note
  87. 171 user not created user created note created Create User

    Destroy User Create Note Destroy Note
  88. 172 user not created user created note created Create User

    Destroy User Create Note Destroy Note
  89. RESET ARC 173 user not created user created note created

    Create User Destroy User Create Note Destroy Note очищает позицию после срабатывания
  90. INHIBITOR ARC 174 user created note created Create User Destroy

    User Create Note Destroy Note разрешает срабатывание перехода только если в позиции нет меток
  91. БЕЗОПАСНЫЕ СЕТИ ПЕТРИ 175 user not created user created note

    created Create User Destroy User Create Note Destroy Note не больше одной метки в позиции
  92. ОБЫЧНЫЕ СЕТИ ПЕТРИ 176 user not created user created note

    created Create User Destroy User Create Note Destroy Note
  93. ЦВЕТНЫЕ СЕТИ ПЕТРИ 177 user not created user created note

    created Create User Destroy User Create Note Destroy Note метка хранит данные
  94. ARC GUARD 178 user not created user created note created

    Create User Destroy User Create Note Destroy Note разрешает срабатывание перехода только если guard = true user is admin
  95. user not created user created Create User Destroy User ИЕРАРХИЧЕСКИЕ

    СЕТИ ПЕТРИ 179 Note note created Create Note Destroy Note