SlideShare a Scribd company logo
1 of 30
Download to read offline
Elixir ExUnit
Brought to you by taotao
1
What
From wiki
In computer programming, unit testing is a software testing method by which
individual units of source code, sets of one or more computer program modules
together with associated control data, usage procedures, and operating
procedures, are tested to determine whether they are fit for use.
Unit testing simply verifies that individual units of code work as expected.
“
2
Why
• improve code quality
• self-confidence
• assurance for modifing
• learning by test cases
3
Outline
• entrance
• cases
• assertions
• callbacks
• mock
• reversed to codes
• coverage
• treat test cases code seriously
4
Entrance
start
Mix will load the test_helper.exs file before executing the tests.
# test/test_helper.exs
ExUnit.start()
5
Cases
options
:async - configures tests in this module to run concurrently with tests in other modules. Tests
in the same module do not run concurrently. It should be enabled only if tests do not change
any global state. Defaults to false.
use ExUnit.Case, async: true
“
6
Cases
test macro
without context:
test "true is equal to true" do
assert true == true
end
7
Cases
context
All tests receive a context as an argument. There are some ways to build the context before
run all test cases in individual test module.
with context:
test "unit test case with context", context do
IO.inspect(context, label: "The context is:")
assert true
end
8
Cases
tags
• timeout
• capture_log
• user-defined tag
9
Assertions
assert
test "unit test assert" do
assert true
assert 1
assert ""
assert !nil
assert !false
assert %{} = %{a: :a, b: :b}
assert %{} != %{a: :a, b: :b}
end
10
Assertions
assert_raise
test "unit test assert_raise" do
assert_raise ArithmeticError, "bad argument in arithmetic expression", fn -> 1 + :a end
assert_raise RuntimeError, fn -> raise "oops" end
end
11
Assertions
assert_receive(d)
test "unit test assert_receive" do
main_pid = self()
spawn(fn ->
Process.sleep(1_000)
send(main_pid, {:ok, self()})
end)
assert_receive {:ok, _}, 2_000
end
test "unit test assert_received" do
send(self(), {:ok, self()})
assert_received {:ok, _}
end
12
Assertions
catch_*
exit/throw
Something about error raising exceptions in EVM
test "unit test assertions catch_*" do
assert catch_exit(exit 1) == 1
assert catch_throw(throw 1) == 1
end
13
Assertions
refute
test "unit test refute" do
refute nil
refute false
end
14
Callbacks
There are many usual callbacks for ExUnit:
• setup
• setup_all
• on_exit
• start_supervised
• stop_supervised
15
Callbacks
purpose
Build context for test case.
The context is a map, can be used in each test case.
test "unit test case with context", context do
IO.inspect(context, label: "The context is:")
assert true
end
16
Callbacks
setup
• Optionally receive a map with test state and metadata.
• All setup callbacks are run before each test.
• Return keyword list / map / {:ok, keywords | map} / :ok .
17
Callbacks
setup
setup do
# IO.puts("Generate random number 1 in setup")
[random_num_1: Enum.random(1..1_000)]
end
setup :generate_random_number_2
defp generate_random_number_2(context) do
# IO.puts("Generate random number 2 in setup")
context
|> Map.put(:random_num_2, Enum.random(1..1_000))
end
test "setup case 1", %{random_num_1: random_num_1, random_num_2: random_num_2} = _context do
IO.puts("The random numbers in case #1 are: {#{random_num_1}, #{random_num_2}}")
assert true
end
test "setup case 2", %{random_num_1: random_num_1, random_num_2: random_num_2} = _context do
IO.puts("The random numbers in case #2 are: {#{random_num_1}, #{random_num_2}}")
assert true
end
18
Callbacks
setup_all
• Optionally receive a map with test state and metadata.
• Return keyword list / map / {:ok, keywords | map} / :ok .
• Invoked only once per module.
19
Callbacks
setup_all
setup_all do
[setup_all_random_num_1: Enum.random(1..1_000)]
end
setup_all :generate_setup_all_random_number_2
defp generate_setup_all_random_number_2(context) do
context
|> Map.put(:setup_all_random_num_2, Enum.random(1..1_000))
end
test "setup_all case 1", %{setup_all_random_num_1: num_1, setup_all_random_num_2: num_2} do
IO.puts("The random numbers in case setup_all #1 are: {#{num_1}, #{num_2}}")
end
test "setup_all case 2", %{setup_all_random_num_1: num_1, setup_all_random_num_2: num_2} do
IO.puts("The random numbers in case setup_all #2 are: {#{num_1}, #{num_2}}")
end
20
Mock
using mock library
21
Mock
mock one module with test
test "unit test mock with one mocked module" do
with_mock(ModuleA, cross_gwf: fn -> :ok end, kill_gwf: fn _ -> true end) do
assert :ok == ModuleA.cross_gwf()
assert true == ModuleA.kill_gwf(nil)
end
end
22
Mock
mock one module with test_with_mock
test_with_mock "unit test mock using macro test_with_mock", ModuleA, [],
cross_gwf: fn -> :ok end,
kill_gwf: fn _ -> true end do
assert :ok == ModuleA.cross_gwf()
assert true == ModuleA.kill_gwf(nil)
end
23
Mock
mock multi-mocked modules
test "unit test mock with multi-mocked modules" do
with_mocks([
{ModuleA, [], [cross_gwf: fn -> :ok end, kill_gwf: fn _ -> true end]},
{ModuleB, [], [cross_gwf: fn -> :ok end, kill_gwf: fn _ -> true end]}
]) do
assert :ok == ModuleA.cross_gwf()
assert true == ModuleA.kill_gwf(nil)
assert :ok == ModuleB.cross_gwf()
assert true == ModuleB.kill_gwf(nil)
end
end
24
Mock
use callback setup_with_mocks
setup_with_mocks([
{ModuleA, [], [cross_gwf: fn -> 1 end, kill_gwf: fn _ -> 2 end]},
{ModuleB, [], [cross_gwf: fn -> 1 end, kill_gwf: fn _ -> 2 end]}
]) do
:ok
end
test "unit test mock use setup with setup with mocks modulea" do
assert 1 == ModuleA.cross_gwf()
assert 2 == ModuleA.kill_gwf(nil)
end
test "unit test mock use setup with setup with mocks moduleb" do
assert 1 == ModuleB.cross_gwf()
assert 2 == ModuleB.kill_gwf(nil)
end
25
Reversed to codes
reasonable input and output for one function
test "unit test for reversed to codes" do
assert :"1" == LearnExunit.to_to_atom(build_params_for_func("1"))
assert :a == LearnExunit.to_to_atom(build_params_for_func("a"))
assert :"1" == LearnExunit.to_atom("1")
assert :a == LearnExunit.to_atom("a")
end
26
Reversed to codes
well-de ned boundaries
defp login_by_email(user, %{password: password} = args) do
login_verify_passwd(is_correct_password?(password), user, args)
end
@doc false
defp login_verify_passwd(true, %{if_mfa: false} = user, args) do
after_login_successfully(user, args, "email", %{})
end
defp login_verify_passwd(true, user, _args) do
{:ok, %{user: user, if_need_verify_mfa: true}}
end
defp login_verify_passwd(false, _, _) do
{:error, %{message: "Password is incorrect.", status: 400}}
end
27
Coverage
Elixir coverage library
28
Treat test cases code seriously
29
30

More Related Content

What's hot

Advanced junit and mockito
Advanced junit and mockitoAdvanced junit and mockito
Advanced junit and mockito
Mathieu Carbou
 
How to debug systemd problems fedora project
How to debug systemd problems   fedora projectHow to debug systemd problems   fedora project
How to debug systemd problems fedora project
Susant Sahani
 
Unit testing with Easymock
Unit testing with EasymockUnit testing with Easymock
Unit testing with Easymock
Ürgo Ringo
 
Mocking in Java with Mockito
Mocking in Java with MockitoMocking in Java with Mockito
Mocking in Java with Mockito
Richard Paul
 
Saving and retrieving_normal_modes_analysis_results
Saving and retrieving_normal_modes_analysis_resultsSaving and retrieving_normal_modes_analysis_results
Saving and retrieving_normal_modes_analysis_results
AltairKorea
 

What's hot (20)

Advanced junit and mockito
Advanced junit and mockitoAdvanced junit and mockito
Advanced junit and mockito
 
An introduction to Google test framework
An introduction to Google test frameworkAn introduction to Google test framework
An introduction to Google test framework
 
JUnit
JUnitJUnit
JUnit
 
How to debug systemd problems fedora project
How to debug systemd problems   fedora projectHow to debug systemd problems   fedora project
How to debug systemd problems fedora project
 
Power mock
Power mockPower mock
Power mock
 
Unit Testing - Nakov's Talk @ VarnaConf 2013
Unit Testing - Nakov's Talk @ VarnaConf 2013Unit Testing - Nakov's Talk @ VarnaConf 2013
Unit Testing - Nakov's Talk @ VarnaConf 2013
 
JUnit Kung Fu: Getting More Out of Your Unit Tests
JUnit Kung Fu: Getting More Out of Your Unit TestsJUnit Kung Fu: Getting More Out of Your Unit Tests
JUnit Kung Fu: Getting More Out of Your Unit Tests
 
Testing with Junit4
Testing with Junit4Testing with Junit4
Testing with Junit4
 
Understanding JavaScript Testing
Understanding JavaScript TestingUnderstanding JavaScript Testing
Understanding JavaScript Testing
 
Testing the waters of iOS
Testing the waters of iOSTesting the waters of iOS
Testing the waters of iOS
 
Junit
JunitJunit
Junit
 
Unit testing with Easymock
Unit testing with EasymockUnit testing with Easymock
Unit testing with Easymock
 
Understanding JavaScript Testing
Understanding JavaScript TestingUnderstanding JavaScript Testing
Understanding JavaScript Testing
 
Mocking in Java with Mockito
Mocking in Java with MockitoMocking in Java with Mockito
Mocking in Java with Mockito
 
Java custom annotations example
Java custom annotations exampleJava custom annotations example
Java custom annotations example
 
Kill the mutants and test your tests - Roy van Rijn
Kill the mutants and test your tests - Roy van RijnKill the mutants and test your tests - Roy van Rijn
Kill the mutants and test your tests - Roy van Rijn
 
Browser testing with nightwatch.js - Drupal Europe
Browser testing with nightwatch.js - Drupal EuropeBrowser testing with nightwatch.js - Drupal Europe
Browser testing with nightwatch.js - Drupal Europe
 
Saving and retrieving_normal_modes_analysis_results
Saving and retrieving_normal_modes_analysis_resultsSaving and retrieving_normal_modes_analysis_results
Saving and retrieving_normal_modes_analysis_results
 
Unit testing with Spock Framework
Unit testing with Spock FrameworkUnit testing with Spock Framework
Unit testing with Spock Framework
 
Spock Framework
Spock FrameworkSpock Framework
Spock Framework
 

Similar to Technical Learning Series - Elixir ExUnit

Unit testing in iOS featuring OCUnit, GHUnit & OCMock
Unit testing in iOS featuring OCUnit, GHUnit & OCMockUnit testing in iOS featuring OCUnit, GHUnit & OCMock
Unit testing in iOS featuring OCUnit, GHUnit & OCMock
Robot Media
 
Selenium with py test by Alexandr Vasyliev for Lohika Odessa Python TechTalks
Selenium with py test by Alexandr Vasyliev for Lohika Odessa Python TechTalksSelenium with py test by Alexandr Vasyliev for Lohika Odessa Python TechTalks
Selenium with py test by Alexandr Vasyliev for Lohika Odessa Python TechTalks
Lohika_Odessa_TechTalks
 

Similar to Technical Learning Series - Elixir ExUnit (20)

Introduction to JUnit
Introduction to JUnitIntroduction to JUnit
Introduction to JUnit
 
Python testing
Python  testingPython  testing
Python testing
 
Unit Testing with JUnit4 by Ravikiran Janardhana
Unit Testing with JUnit4 by Ravikiran JanardhanaUnit Testing with JUnit4 by Ravikiran Janardhana
Unit Testing with JUnit4 by Ravikiran Janardhana
 
Junit 4.0
Junit 4.0Junit 4.0
Junit 4.0
 
Junit_.pptx
Junit_.pptxJunit_.pptx
Junit_.pptx
 
We Are All Testers Now: The Testing Pyramid and Front-End Development
We Are All Testers Now: The Testing Pyramid and Front-End DevelopmentWe Are All Testers Now: The Testing Pyramid and Front-End Development
We Are All Testers Now: The Testing Pyramid and Front-End Development
 
Junit With Eclipse
Junit With EclipseJunit With Eclipse
Junit With Eclipse
 
JMockit
JMockitJMockit
JMockit
 
Unit testing in iOS featuring OCUnit, GHUnit & OCMock
Unit testing in iOS featuring OCUnit, GHUnit & OCMockUnit testing in iOS featuring OCUnit, GHUnit & OCMock
Unit testing in iOS featuring OCUnit, GHUnit & OCMock
 
Selenium with py test by Alexandr Vasyliev for Lohika Odessa Python TechTalks
Selenium with py test by Alexandr Vasyliev for Lohika Odessa Python TechTalksSelenium with py test by Alexandr Vasyliev for Lohika Odessa Python TechTalks
Selenium with py test by Alexandr Vasyliev for Lohika Odessa Python TechTalks
 
Unit testing by Svetlin Nakov
Unit testing by Svetlin NakovUnit testing by Svetlin Nakov
Unit testing by Svetlin Nakov
 
Lecture (Software Testing).pptx
Lecture (Software Testing).pptxLecture (Software Testing).pptx
Lecture (Software Testing).pptx
 
Unit testing patterns for concurrent code
Unit testing patterns for concurrent codeUnit testing patterns for concurrent code
Unit testing patterns for concurrent code
 
JAVASCRIPT TDD(Test driven Development) & Qunit Tutorial
JAVASCRIPT TDD(Test driven Development) & Qunit TutorialJAVASCRIPT TDD(Test driven Development) & Qunit Tutorial
JAVASCRIPT TDD(Test driven Development) & Qunit Tutorial
 
Test driven development
Test driven developmentTest driven development
Test driven development
 
8-testing.pptx
8-testing.pptx8-testing.pptx
8-testing.pptx
 
MT_01_unittest_python.pdf
MT_01_unittest_python.pdfMT_01_unittest_python.pdf
MT_01_unittest_python.pdf
 
Python: Object-Oriented Testing (Unit Testing)
Python: Object-Oriented Testing (Unit Testing)Python: Object-Oriented Testing (Unit Testing)
Python: Object-Oriented Testing (Unit Testing)
 
Unit test-using-spock in Grails
Unit test-using-spock in GrailsUnit test-using-spock in Grails
Unit test-using-spock in Grails
 
Building unit tests correctly with visual studio 2013
Building unit tests correctly with visual studio 2013Building unit tests correctly with visual studio 2013
Building unit tests correctly with visual studio 2013
 

More from ArcBlock

More from ArcBlock (18)

ArcBlock Introduction to Blockchain
ArcBlock Introduction to BlockchainArcBlock Introduction to Blockchain
ArcBlock Introduction to Blockchain
 
Forge blockchain deployment made easy
Forge  blockchain deployment made easyForge  blockchain deployment made easy
Forge blockchain deployment made easy
 
Designing Decentralized Apps: Programmable Tokens
Designing Decentralized Apps: Programmable TokensDesigning Decentralized Apps: Programmable Tokens
Designing Decentralized Apps: Programmable Tokens
 
Build a Decentralized, public verifiable Database with ex_abci and Tendermint
Build a Decentralized, public verifiable Database with ex_abci and TendermintBuild a Decentralized, public verifiable Database with ex_abci and Tendermint
Build a Decentralized, public verifiable Database with ex_abci and Tendermint
 
ArcBlock Presents 5 Winning Factors to Building a Successful DApp
ArcBlock Presents 5 Winning Factors to Building a Successful DAppArcBlock Presents 5 Winning Factors to Building a Successful DApp
ArcBlock Presents 5 Winning Factors to Building a Successful DApp
 
QRCodes are Fun, Easy, and Useful for Links, Payments and Identity Verification
QRCodes are Fun, Easy, and Useful for Links, Payments and Identity VerificationQRCodes are Fun, Easy, and Useful for Links, Payments and Identity Verification
QRCodes are Fun, Easy, and Useful for Links, Payments and Identity Verification
 
Designing Decentralized Applications (DApps)
Designing Decentralized Applications (DApps) Designing Decentralized Applications (DApps)
Designing Decentralized Applications (DApps)
 
Cryptography for everyone
Cryptography for everyoneCryptography for everyone
Cryptography for everyone
 
Introduction to HTTP/2 and How To Use It
Introduction to HTTP/2 and How To Use ItIntroduction to HTTP/2 and How To Use It
Introduction to HTTP/2 and How To Use It
 
IPFS: A Whole New World
IPFS: A Whole New WorldIPFS: A Whole New World
IPFS: A Whole New World
 
Ethereum virtual machine for Developers Part 1
Ethereum virtual machine for Developers Part 1Ethereum virtual machine for Developers Part 1
Ethereum virtual machine for Developers Part 1
 
Understanding hd wallets design and implementation
Understanding hd wallets  design and implementationUnderstanding hd wallets  design and implementation
Understanding hd wallets design and implementation
 
Tendermint in a nutshell
Tendermint in a nutshellTendermint in a nutshell
Tendermint in a nutshell
 
Introduction to CQRS & Commended
Introduction to CQRS & CommendedIntroduction to CQRS & Commended
Introduction to CQRS & Commended
 
Decipher Multi-Factor Authentication - A Developers Introduction
Decipher Multi-Factor Authentication - A Developers IntroductionDecipher Multi-Factor Authentication - A Developers Introduction
Decipher Multi-Factor Authentication - A Developers Introduction
 
Introduction to aws data pipeline services
Introduction to aws data pipeline servicesIntroduction to aws data pipeline services
Introduction to aws data pipeline services
 
Introduction to Ethereum Smart Contracts
Introduction to Ethereum Smart Contracts Introduction to Ethereum Smart Contracts
Introduction to Ethereum Smart Contracts
 
ArcBlock Presents An Introduction to Blockchain
ArcBlock Presents An Introduction to BlockchainArcBlock Presents An Introduction to Blockchain
ArcBlock Presents An Introduction to Blockchain
 

Recently uploaded

%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
masabamasaba
 

Recently uploaded (20)

WSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
WSO2Con2024 - Enabling Transactional System's Exponential Growth With SimplicityWSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
WSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
 
WSO2CON2024 - Why Should You Consider Ballerina for Your Next Integration
WSO2CON2024 - Why Should You Consider Ballerina for Your Next IntegrationWSO2CON2024 - Why Should You Consider Ballerina for Your Next Integration
WSO2CON2024 - Why Should You Consider Ballerina for Your Next Integration
 
Artyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptxArtyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptx
 
WSO2Con2024 - Unleashing the Financial Potential of 13 Million People
WSO2Con2024 - Unleashing the Financial Potential of 13 Million PeopleWSO2Con2024 - Unleashing the Financial Potential of 13 Million People
WSO2Con2024 - Unleashing the Financial Potential of 13 Million People
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 
WSO2Con2024 - Software Delivery in Hybrid Environments
WSO2Con2024 - Software Delivery in Hybrid EnvironmentsWSO2Con2024 - Software Delivery in Hybrid Environments
WSO2Con2024 - Software Delivery in Hybrid Environments
 
WSO2CON 2024 - Designing Event-Driven Enterprises: Stories of Transformation
WSO2CON 2024 - Designing Event-Driven Enterprises: Stories of TransformationWSO2CON 2024 - Designing Event-Driven Enterprises: Stories of Transformation
WSO2CON 2024 - Designing Event-Driven Enterprises: Stories of Transformation
 
WSO2Con2024 - GitOps in Action: Navigating Application Deployment in the Plat...
WSO2Con2024 - GitOps in Action: Navigating Application Deployment in the Plat...WSO2Con2024 - GitOps in Action: Navigating Application Deployment in the Plat...
WSO2Con2024 - GitOps in Action: Navigating Application Deployment in the Plat...
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
AzureNativeQumulo_HPC_Cloud_Native_Benchmarks.pdf
AzureNativeQumulo_HPC_Cloud_Native_Benchmarks.pdfAzureNativeQumulo_HPC_Cloud_Native_Benchmarks.pdf
AzureNativeQumulo_HPC_Cloud_Native_Benchmarks.pdf
 
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open Source
WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open SourceWSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open Source
WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open Source
 
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
 
WSO2Con2024 - Facilitating Broadband Switching Services for UK Telecoms Provi...
WSO2Con2024 - Facilitating Broadband Switching Services for UK Telecoms Provi...WSO2Con2024 - Facilitating Broadband Switching Services for UK Telecoms Provi...
WSO2Con2024 - Facilitating Broadband Switching Services for UK Telecoms Provi...
 
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
 
WSO2CON 2024 - Building a Digital Government in Uganda
WSO2CON 2024 - Building a Digital Government in UgandaWSO2CON 2024 - Building a Digital Government in Uganda
WSO2CON 2024 - Building a Digital Government in Uganda
 
WSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go Platformless
 
WSO2CON 2024 - Architecting AI in the Enterprise: APIs and Applications
WSO2CON 2024 - Architecting AI in the Enterprise: APIs and ApplicationsWSO2CON 2024 - Architecting AI in the Enterprise: APIs and Applications
WSO2CON 2024 - Architecting AI in the Enterprise: APIs and Applications
 

Technical Learning Series - Elixir ExUnit

  • 1. Elixir ExUnit Brought to you by taotao 1
  • 2. What From wiki In computer programming, unit testing is a software testing method by which individual units of source code, sets of one or more computer program modules together with associated control data, usage procedures, and operating procedures, are tested to determine whether they are fit for use. Unit testing simply verifies that individual units of code work as expected. “ 2
  • 3. Why • improve code quality • self-confidence • assurance for modifing • learning by test cases 3
  • 4. Outline • entrance • cases • assertions • callbacks • mock • reversed to codes • coverage • treat test cases code seriously 4
  • 5. Entrance start Mix will load the test_helper.exs file before executing the tests. # test/test_helper.exs ExUnit.start() 5
  • 6. Cases options :async - configures tests in this module to run concurrently with tests in other modules. Tests in the same module do not run concurrently. It should be enabled only if tests do not change any global state. Defaults to false. use ExUnit.Case, async: true “ 6
  • 7. Cases test macro without context: test "true is equal to true" do assert true == true end 7
  • 8. Cases context All tests receive a context as an argument. There are some ways to build the context before run all test cases in individual test module. with context: test "unit test case with context", context do IO.inspect(context, label: "The context is:") assert true end 8
  • 10. Assertions assert test "unit test assert" do assert true assert 1 assert "" assert !nil assert !false assert %{} = %{a: :a, b: :b} assert %{} != %{a: :a, b: :b} end 10
  • 11. Assertions assert_raise test "unit test assert_raise" do assert_raise ArithmeticError, "bad argument in arithmetic expression", fn -> 1 + :a end assert_raise RuntimeError, fn -> raise "oops" end end 11
  • 12. Assertions assert_receive(d) test "unit test assert_receive" do main_pid = self() spawn(fn -> Process.sleep(1_000) send(main_pid, {:ok, self()}) end) assert_receive {:ok, _}, 2_000 end test "unit test assert_received" do send(self(), {:ok, self()}) assert_received {:ok, _} end 12
  • 13. Assertions catch_* exit/throw Something about error raising exceptions in EVM test "unit test assertions catch_*" do assert catch_exit(exit 1) == 1 assert catch_throw(throw 1) == 1 end 13
  • 14. Assertions refute test "unit test refute" do refute nil refute false end 14
  • 15. Callbacks There are many usual callbacks for ExUnit: • setup • setup_all • on_exit • start_supervised • stop_supervised 15
  • 16. Callbacks purpose Build context for test case. The context is a map, can be used in each test case. test "unit test case with context", context do IO.inspect(context, label: "The context is:") assert true end 16
  • 17. Callbacks setup • Optionally receive a map with test state and metadata. • All setup callbacks are run before each test. • Return keyword list / map / {:ok, keywords | map} / :ok . 17
  • 18. Callbacks setup setup do # IO.puts("Generate random number 1 in setup") [random_num_1: Enum.random(1..1_000)] end setup :generate_random_number_2 defp generate_random_number_2(context) do # IO.puts("Generate random number 2 in setup") context |> Map.put(:random_num_2, Enum.random(1..1_000)) end test "setup case 1", %{random_num_1: random_num_1, random_num_2: random_num_2} = _context do IO.puts("The random numbers in case #1 are: {#{random_num_1}, #{random_num_2}}") assert true end test "setup case 2", %{random_num_1: random_num_1, random_num_2: random_num_2} = _context do IO.puts("The random numbers in case #2 are: {#{random_num_1}, #{random_num_2}}") assert true end 18
  • 19. Callbacks setup_all • Optionally receive a map with test state and metadata. • Return keyword list / map / {:ok, keywords | map} / :ok . • Invoked only once per module. 19
  • 20. Callbacks setup_all setup_all do [setup_all_random_num_1: Enum.random(1..1_000)] end setup_all :generate_setup_all_random_number_2 defp generate_setup_all_random_number_2(context) do context |> Map.put(:setup_all_random_num_2, Enum.random(1..1_000)) end test "setup_all case 1", %{setup_all_random_num_1: num_1, setup_all_random_num_2: num_2} do IO.puts("The random numbers in case setup_all #1 are: {#{num_1}, #{num_2}}") end test "setup_all case 2", %{setup_all_random_num_1: num_1, setup_all_random_num_2: num_2} do IO.puts("The random numbers in case setup_all #2 are: {#{num_1}, #{num_2}}") end 20
  • 22. Mock mock one module with test test "unit test mock with one mocked module" do with_mock(ModuleA, cross_gwf: fn -> :ok end, kill_gwf: fn _ -> true end) do assert :ok == ModuleA.cross_gwf() assert true == ModuleA.kill_gwf(nil) end end 22
  • 23. Mock mock one module with test_with_mock test_with_mock "unit test mock using macro test_with_mock", ModuleA, [], cross_gwf: fn -> :ok end, kill_gwf: fn _ -> true end do assert :ok == ModuleA.cross_gwf() assert true == ModuleA.kill_gwf(nil) end 23
  • 24. Mock mock multi-mocked modules test "unit test mock with multi-mocked modules" do with_mocks([ {ModuleA, [], [cross_gwf: fn -> :ok end, kill_gwf: fn _ -> true end]}, {ModuleB, [], [cross_gwf: fn -> :ok end, kill_gwf: fn _ -> true end]} ]) do assert :ok == ModuleA.cross_gwf() assert true == ModuleA.kill_gwf(nil) assert :ok == ModuleB.cross_gwf() assert true == ModuleB.kill_gwf(nil) end end 24
  • 25. Mock use callback setup_with_mocks setup_with_mocks([ {ModuleA, [], [cross_gwf: fn -> 1 end, kill_gwf: fn _ -> 2 end]}, {ModuleB, [], [cross_gwf: fn -> 1 end, kill_gwf: fn _ -> 2 end]} ]) do :ok end test "unit test mock use setup with setup with mocks modulea" do assert 1 == ModuleA.cross_gwf() assert 2 == ModuleA.kill_gwf(nil) end test "unit test mock use setup with setup with mocks moduleb" do assert 1 == ModuleB.cross_gwf() assert 2 == ModuleB.kill_gwf(nil) end 25
  • 26. Reversed to codes reasonable input and output for one function test "unit test for reversed to codes" do assert :"1" == LearnExunit.to_to_atom(build_params_for_func("1")) assert :a == LearnExunit.to_to_atom(build_params_for_func("a")) assert :"1" == LearnExunit.to_atom("1") assert :a == LearnExunit.to_atom("a") end 26
  • 27. Reversed to codes well-de ned boundaries defp login_by_email(user, %{password: password} = args) do login_verify_passwd(is_correct_password?(password), user, args) end @doc false defp login_verify_passwd(true, %{if_mfa: false} = user, args) do after_login_successfully(user, args, "email", %{}) end defp login_verify_passwd(true, user, _args) do {:ok, %{user: user, if_need_verify_mfa: true}} end defp login_verify_passwd(false, _, _) do {:error, %{message: "Password is incorrect.", status: 400}} end 27
  • 29. Treat test cases code seriously 29
  • 30. 30