Write Unit Tests in Rust 🦀 Rust Programming Tutorial for Developers
- November 5, 2023
- Posted by: MainInstructor
- Category: Amazon Web Services BASIC Go Rust
Video Title: Write Unit Tests in Rust 🦀 Rust Programming Tutorial for Developers
Hey guys my name is Trevor Sullivan and welcome back to my video channel thank you so much for joining me for yet another video in our rust programming tutorial series now in the last video in this playlist I actually covered a topic that Fells kind of outside the realm of
Just the rust core programming language and standard library and in that video we covered Amazon web services SDK with rust and how you can automate things in the rust a the AWS apis but we’re actually going to go back and focus really on the core of rust itself and
We’re going to be specifically talking about how to test your rust code when you create a rust project or crate for your application or Library so over in the rust programming language book here there’s a section in section 11 it talks about how to write automated tests so
This goes into some of the fundamental behind how to write tests in particular you’re going to notice that there is this attribute that you can apply to a module called CFG and then CFG actually takes an input argument and if you set that to test then that will restrict
That entire module to only be executed or compiled when you actually run a cargo test CLI command so when you want to run tests you use the cargo CLI tool in the past we’ve been using cargo build or cargo run to compile or execute our project but there’s another command
Called the cargo test command that allows us to execute our automated tests in our binary application project or in a library project for a crate that you’ve created now we also have another attribute that we want to pay attention to here and this is the test annotation attribute and this allows you to
Designate a specific function as a test that needs to be executed by the cargo CLI so even though you’ve declared this CFG up here at the module level you also need to annotate your individual tests as well and tests at the end of the day are literally just functions so a
Function is a test a test is a function it’s kind of the same concept there but when the cargo CLI is going through your source code and actually looking for different tests to execute it’ll look for this right here and it’ll also look for for this test right here now this
CFG test here is actually a little bit more of an exclusion than an inclusion because by default if you have a module right here and you tell cargo to build your project then that module is actually going to get included in the resulting binary that gets produced by
The build process right so when we specify CFG test here what we’re actually doing is we’re saying we want to exclude this particular seg segment of code this entire module from our comp compiled binary when it produces that complete binary because this is exclusively for testing purposes and so
That’s what helps to keep our binary sizes smaller as well as improving our compilation times now as I mentioned the function that you write here is basically the test itself and there’s a few different assertion macros that we can use that help help us to determine
If a particular condition is met so we have assert equals here in this particular example but then if you go out to the rust standard Library let’s just do a search for rust standard here and then we’ll just do a search for assert in here and as you can see under
Macros here there is an assert macro there’s assert equal assert not equal and things like that so those are some different assertions that we can use inside of our test functions to actually return either are a true passing result or successful result or a failure result
Or false in the case that the test does not actually pass so that’s really the basic structure of our tests here so what we’re going to do is actually write some code that utilizes the technique right here in the documentation and then we’re also going to take a look at this
Cargo test CLI tool that helps us to execute tests now one other interesting type of test that you can run aside from these unit tests right here is something called a dock test so what’s really interesting is that you can actually embed code samples inside of your documentation and we actually talked
About doc strings in a different video but what you can do is embed a code sample in your documentation strings and then the cargo CLI will actually seek out those code Snippets in your documentation and it will execute them just like test functions so you have the
Option of right right writing your unit test functions like regular rust functions and including them as a test using the test attribute here but you also have the option of specifying your tests in the doc strings as well now I’m not quite as much of a fan as of the doc
Strings as I am of writing regular functions here because the intellisense that you get from the rust analyzer isn’t going to work properly you’re not going to get syntax highlighting and all of those nice language features so generally speaking I would recommend avoiding dock strings in favor of using
Just standard functions in Rust for your automated tests but it’s really up to you what route you want to go so before we actually jump in and start some Hands-On coding here I just wanted to ask you to support this channel by liking this video subscribing and leaving a comment down below this
Channel is kind of sponsored by you the viewers right I don’t get paid specifically to create any content content on this channel so any kind of support you can provide would be awesome also I have an affiliate link to an Amazon store down below so any orders
That you place through that Amazon store will go towards supporting this channel as well all right let’s go ahead and jump in and start writing some code so I am sshed from VSS code into my rust 2 Dev system here so what we’re going to do for starters is just as we typically
Do create a new project for our tests here so I’ll say cargo new sample Das tests and then we’ll go ahead and open that up so I’ll do contrl KR o and then we’ll open up the sample tests directory here so this created a new binary project so it’s an application that we
Can build and execute as opposed to a library project which is just a crate containing a library of functions and data structures and traits and things of that nature that are exported from it and so if we go into our main. RS file here as we typically know from other
Videos in this playlist you’ve probably seen this this is just our entry point into our application so if we do a cargo run here it’s just going to run the main function and we’ll get our result here but let’s say that we want to build out some additional helper functions and
Then write some tests against those functions right so I’m just going to get rid of the standard hello world print line statement here and instead I’m going to declare a function that allows us to accept a couple of input arguments and then it’ll return a value back to
The caller and then this function will serve as a basis for our automated tests that we’ll build out after we actually build the core functionality so I’m going to create a function here in the same main module here and we’ll call it get full name and then I want to accept
A couple of input arguments so I want to take a person’s first name and their last name and then I want to join those together with a space in between and that will be the resulting output from this function so we have two input arguments first and last name and then
We also need to declare the return type from the function so let’s take the first name as a string slice we’ll take the last name as a string slice as well and we’re going to return a string type here now we’re going to get this error saying mismatch types because we
Declared a string return type but we are not actually returning any value from the function body thus far so we actually need to implement the function and this error will go away so what we’re going to do is inside of the body of this function we’re just going to
Create a new string so we’ll say let result equal nothing just an empty string basically and then we’ll take that string let’s actually declare it as a string type here and then we’ll do dot 2 string here as well that’ll turn the string slice into a capital S string
That’s allocated on the Heap so it’s dynamically sized and then what we can do is say result. push string and then we’ll start by pushing the first name onto the end of this string so what we’re going to do is add a space so we’re actually going to do push string
Several different times here so we’re going to add a space second and then third we’re going to add the last name so we’re going to start by pushing first then we’ll add a space and then finally we’ll push the last name back to this string all right so now what we can do
Is return the result back to the color and because we are mutating the string we also need to designate it as a mutable or modifiable or alterable whatever word you want to use to describe it but we need to make our string mutable here because we are actually modifying the underlying value
Of the string by using the push Str function call here here all right so then finally we just return that string object back to our caller and that should fulfill the function signature here right so what I’m going to do is just say print line and then we’ll pass
In a call to get full name and we’ll pass in Trevor and Sullivan so first name and last name so now if we do a cargo run you can see that we get first name space last name from our helper function right here but now we want to
Do some automated testing around our helper function we want to validate the inputs and we want to be able to validate the outputs from this function as well to assert or ensure that the given inputs produce the expected outputs right because what if somebody imported this function from my crate
Library and tried to pass in some really bizarre inputs right so maybe they do something like a you know a carrot character or maybe they do a dollar sign maybe they do a number three in there somewhere right they just really mangle the inputs into this function right so I
Need to ensure that my function that I write is uh very robust and that it’s going to be able to handle these different types of situations right so one thing that we could do in the case of somebody passing in some invalid input here would be to Simply Panic the
Program and abort execution right so we could actually assert from an automated test that the function get full name panics and causes the application to terminate right so what I’m going to do is create a separate module down here so we’ll call this mod my tests and in this
Custom module that we’re creating as a child module of the main module what we want to do is Define our unit tests here so for starters we’re going to add the CFG attribute up here and specify that this is a test module and again when we
Do a cargo build or a cargo run that causes a build to occur then this entire test Suite will be excluded from that final build because we don’t want to include the test code in a production binary that we are Distributing to any clients that want to consume that
Library or that command line utility right so what we want to do is declare that CFG test argument there uh attribute and then what’re going to do is write a bunch of individual functions that perform different tests against my get full name function so what we’ll do
Is say FN test get full name normal input and what we’re going to do inside of this function body after we designate it as a test to make it discoverable by the cargo test CLI tool is we’re going to call Super get full name now you’re probably wondering what is super right
What does that mean well remember that within the main module that we have right here in the main. RS file we have a child module called my tests so in order for this child module to reference a function that has been declared in the parent scope so in the main module the
Main module is the parent of the my tests module here so in order to reference that parent module the main module we have to use the super keyword here and that is going to dynamically go up a step and grab whatever that parent module is and then we can simply call
The function using that super something else that we could do is to say use super star and then that will import anything that’s declared within the parent module into our local test module and so in that case I can just call get full name directly and even though we’re
Getting an error here here that’s not coming from the function name that’s coming from the arguments that are being passed in here so this is valid syntax where I can import everything from the parent module and then I can just use those functions as if they were local
Inside of the child module so what I’m going to do is go ahead and just eliminate this for Simplicity and I’m going to say super because that’s just very explicit in my code and then I’m going to pass in a first name as a string slice and a last name as a string
Slice now I expect that this is going to succeed right so what I’m going to do is use this assert equal here and I’m going to assign the result so let’s say let result equal the result from that function and then I’m going to check that result is equal to Trevor space
Sullivan so I’m passing in two different arguments I want to check the output from the function which is assigned to this result variable and then I’m going to to compare it to a hard-coded string inside of my test Library so now if I do a cargo test command it’s going to
Automatically detect the tests inside of my program inside of my crate because I designated them with this test attribute now what you’ll notice is that if I actually comment out or just outright remove that CFG annotation on the module the test is still detected because I annotated it with this test attribute
Here but again if I want to exclude this test module from my final build my production build that I distribute to other users then the CFG attribute here is what’s going to allow me to do that exclusion so I’m not bloating up my binary that I distribute
Out to other users with all of my test code right so this test attribute here is really essential for cargo test in to locate those tests right so if I were to remove that and then try to run cargo test you’re going to see that zero tests
Were executed because cargo test did not detect any tests inside of my project so we need to make sure that we leave that test attribute inside of there now this is a perfectly normal output so we expected to get this result we expect that this test is going to pass because
We passed in a normal first name and a normal last name now what but if we go back to the example where we pass in some mangled input right we don’t want our function to execute if we have this mangled input we want to maybe Panic or
You know throw some kind of error message as part of a result object or something of that nature right so what we can do is write another test down here and pass in some mangled output to see what kind of result we get and we can actually declare the result that we
Expect very similar to a asserting that the result of the function call equals a particular value here so what we’ll do is write another test and we’ll say test get full name mangled well let’s actually just say maybe special cars and then we’re going to basically
Do the same thing here where we call the get full name function from the super module which again is the main module and this time I’m not going to assign the result because I don’t actually need to check the return value in fact I’m not even expecting that this function is
Going to return at all I’m actually going to expect that if I pass in some mangled input with weird special characters interspersed into either the first name or the last name I’m going to expect that this function will panic and abort execution okay so in that case I
Don’t even need to check the return value because the function should terminate before that return value is ever received right and the reason that we can do these tests and panic without having to worry about impacting tests is because when you do a cargo test the by default the tests themselves are
Individually executed in separate threads so cargo itself is running in one thread it’s it’s executing your kind of main entry point in one thread and then all of the individual tests are actually kicked off and spawned in external threads and I actually have another video that goes into depth about
Threads in Rust so I would strongly encourage you to study that topic because it’s a really good concept to know as you’re writing rust applications that you need to be high performance so what we’re going to do now is add in another attribute and we haven’t covered this yet but there is an
Attribute that allows us to check to see if there is a panic from the function right and so what we’re going to do is use this type down here called should panic and if we use should Panic on our function call then that is going to
Check to see if it panics or not so let me just do should Panic here because there’s a lot of other Panic related stuff and So within testing we can use should Panic to determine if it’s going to Panic or not so what we’ll do is back
In our code right here we’re going to add in another attribute and we’re going to use should Panic so in this case rather than using an assertion to assert that the return value matches some hardcoded value inside of our test we’re actually just going to say you know what
I’m going to kick off this function with these inputs and somewhere inside that function I am expecting the function to panic and throw an error right so what we’re going to do is pass in these invalid inputs and hopefully our function will Panic right so we’ll do
Cargo test and as you can see right down here it actually failed because the function did not panic but we expected it to panic right so now we have two tests we have one test that passed that’s our test with normal inputs and now now we have one test that has failed
Because it didn’t Panic right so now we’ve already declared our test that shows what our desired functionality is but our function get full name doesn’t actually match the desired functionality from the tests so it’s up to us as developers of rust applications to come in here find the get full name function
And fix whatever is wrong with that function that’s causing it to not behave as expected so what we’ll do is check to see if the first name contains certain characters and so what we can do is call this contains function so on a string slice it has a contains function that
Allows us to check to see if it contains certain characters so we can pass in a string slice we can also pass in a slice of cars and we can also pass in a closure so it also supports passing in a closure that determines if a character
Matches or not so what I’m going to do here is just create a string or a slice of actually an array uh no this is going to be a slice cars actually and so what we’re going to do is check to see if any of these special characters
Are detected inside of this string so what else did we have down here we had a Amper sand a carrot and an asterisk so I think we’ve got all of those as long as I add in the Amper sand there so then what we’ll do is that is say if the
First name contains any of these weird special characters if that returns true then we want to call the Panic macro and say first name cannot contain special characters all right so what we’re doing is we’re checking the input here and doing some validation on it so that if
There is some invalid input if there’s some if maybe a hacker is trying to throw a bunch of buzzed input data into our function and trying to crack it and trying to break into an application or break into a system then we’re actually going to do some sanitization we’re
Going to sanitize our inputs and make sure that we’re writing safe code that only accepts the expected inputs and so these weird special characters are not part of our standard inputs we could add more things like maybe the pipe character or maybe a plus sign and a
Minus sign as well those are all characters that we don’t want to see so you can build out as many characters as you want to in the string slice and do a comparison by using the this contains function right so right up here this one should actually cause a panic to occur
Because it has a carrot or hat character there and same thing with this one down here this should Now fail because it is the test should actually pass because the function is now panicking as a result of that invalid input so if we run our test again now you can see that
Test get full name special cars is now passing so now we have two passing tests now this is only doing partially what we expect it to because we’re only checking to see if the first name contains these particular special characters right so if we were to write another
Test so we’ll say test get full name first name special cars but now what if we pass in some special cars into the last name right so the first and the last name are both going to have special cards here actually we already have a test for the first name so I’m just
Going to do a normal input for first name and now we’re going to pass in some weird characters for last name so now if we do cargo test we now have a total of three tests two of those tests are passing and one of those tests is failing because now this time we’re
Passing in some weird characters for the last name input argument but nowhere inside of this function are we panicking if the last name contains any of these characters so what I’m going to do is just duplicate this code down here yes there are more efficient ways of doing
This like maybe doing uh let pattern equal this and then we can reuse the pattern here so let’s just pass in pattern and then say if last contains pattern then we can say last name cannot contain special characters so now we have a unique Panic for our first name
That’s invalid and now we have a panic for the last name if the last name does not match the expected inputs so now if we do cargo test let’s go ahead and rename this to last name special cars just so we know exactly what that’s testing and now all of our tests are
Passing here so last name is checking out first name is checking out and normal inputs are also checking out so this is kind of how we can build up a library of tests and make sure that any time that we change something about how our code functions that our tests are
Not going to break you can incorporate the cargo test command in your cicd pipelines if you’re using something like GitHub actions or Azure devops or you know code build in AWS or gitlab cicd or maybe tekon or there’s a whole bunch of cicd tools out there so you can include
The cargo test CLI command in your cicd pip P lines and if any of your tests fail you should get a nonzero exit code so let’s go ahead and actually do something like comment out this Panic here that’ll cause the test to fail once again and if we Echo out the last return
Code you can see it’s actually 101 which indicates that it’s a failure because it’s a nonzero code and so you could abort your cicd pipeline if that error message appears as The Last Exit code from your app and that just helps you to write more robust code right you don’t want to
Release code that has bugs inside of it so we can simply check that in our cicd Pipeline and make sure that our code is as robust as possible now let’s talk about how we can move these tests into a separate file I already did a video on modules in Rust
That’s one of my earlier videos in this rust programming tutorial playlist so please go check that out but what we we can do is extract all of these tests and put them into a separate file so what we could do is create a file here called
Maybe main tests. RS and we could put this inside of this file but now that we have a separate module we don’t need to declare the module using that module scope there so we’ll just dind all of our tests right here and then the other thing that we want to do is actually
Move this CFG up to the top here but because the module is now the outer component right the module is the file itself so we need to apply this CFG attribute to the outer module not the inner module right so previously when we declared the module we just did a
Hashtag which means apply this attribute to the following item but now because the CFG needs to apply to the outer item not the following item in the list of lines of source code here we need to actually do hash exclamation point and that will apply the CFG attribute to the
Entire main tests module file rather than specifying it as a code block so now when we do a cargo test you can see that no tests are being detected here and that’s because our main fun our main module here is not referencing main tests so let’s go ahead and reference
That module and now once again you can see that our tests are executing because cargo is aware that our main module is referencing the test module but when we do a cargo build the tests will not be included in the resulting binary all right so that’s how we can
Separate our tests into a separate file so that’s a really nice way to just kind of organize your code you can have a you know a module like Main and then a test file called main tests. RS just make sure that you reference those modules from your main
Module all right so one other thing that I wanted to cover is how to do dock testing so this is unfortunately only supported in library crates not binary crates so if I wanted to write a test a doc test let’s say that I went ahead and did you know triple forward slashes here
And then the way that we Define a doc test is to specify three TIY characters and then in between those three characters which is very similar to uh markdown syntax that we would use to write markdown code blocks then we can write the code right inside of here so
We could say let full name equal get full name and we could pass in Trevor and then Jones and then we could say assert and we’ll say full name equals Trevor Jones so even though this code is inside of the documentation here we can actually test it by using the cargo test
Command but as I mentioned it’s only supported in libraries so if you were to try to do a cargo test command here let’s do cargo test- dhel and then if you see right here there’s this– doc par parameter that allows us to test the libraries documentation and this is
Really important to pay attention to because it says test the libraries documentation not the applications or not the binary entry point documentation so it has to be a library so if we try to do a cargo test– doc right here you can see it says no Library targets found
In package and then the package name that you tried to run that’s our crate name right that’s our folder name so in order for us to properly write this we actually have to create a library instead so what we’re going to do is just move this entire function actually
So let’s grab grab the function along with all the documentation and then we’re going to create a file called li. RS so now what we’re doing is creating a library inside of our crate rather than simply incorporating that into the main function so now what we can do is
Reference our library by doing sample tests and then get full name but we also need to make this function public because now it’s part of a library we need to make sure that that function is exported from the library so that we can consume it in the application so it’s a
Little bit weird here but just so you understand the crate that we’ve created called sample Das tests actually has two different components to it it actually has a binary entry point called main. RS and it also has a library called li. RS and crates can only Define one library
But they can actually Define many different application and entry points that’s something that’s kind of interesting about crates is that you can have many many different binaries but only one Library so it might look like we have a circular reference here where the main entry point is referencing
Sample tests but that is actually just a reference to the library called li. RS and then we also need to fix our tests over here so we’ll say sample tests and fix the references to that function to make sure that our tests are working correctly as well and so now we’ll do a
Cargo test– Dock and also we need to fix our reference right here to get full name so let’s go ahead and say sample tests get full name and hopefully that should work awesome so as you can see this time only one test executed and that is because we specified that we
Only want to run the doc tests we don’t want to run regular tests we only want the doc tests there is another parameter here called D- tests and this allows us to test all tests right and so if we specify cargo test– tests then that’s going to
Execute our regular tests not doc tests not example code not Benchmark code there’s actually several different types of tests we have the doc tests we have examples we have benchmarks and we have the standard unit tests that we wrote over in this main tests file right here
So that’s a little bit about how testing works just be aware that tests are executed in their own threads by default and if you do want to actually specify that you want the tests to execute inside of a single thread there is actually a way to do
That let’s take a look at the help here I think it’s actually in a SE separate section let’s just do a quick search for thread yeah so it’s going to happen if we try to run against a binary here so what we’re going to do is say cargo run or actually
Cargo test I think that’s my problem here cargo test Das Dash and then d-el and the reason that we have to do this is because you can pass certain command line arguments to Cargo test like Das – do that’s a parameter that gets passed to the cargo test CLI tool but if you
Want to pass a argument to the actual test binary that gets generated then you actually have to put a Dash Dash as a separator and the way that we know that is when you do cargo test– help you can actually see that there is a dash dash
Here and then any arguments after the dash dash are going to get passed to the test binary not to the cargo test command so if I do cargo test and then D Dash and then d-el those are going to those are going to be the arguments that
We can pass into the test binary that’s generated when we compile the tests with cargo test and so what we can do is either set this environment variable called rust test threads or we can specify D Dash test threads here so if we do test threads equal 1 now only a
Single thread is going to be spawned for those tests rather than spawning a separate thread for every single test right so you do have the ability to specify how many threads you want to use for executing your tests but in any case that’s I think pretty much everything
That I wanted to cover as far as testing goes for now hopefully you learned something new from this video if you did learn something new please leave a thumbs up please leave a comment down below let me know what you thought of this video and let me know what other
Ideas you have for other videos that I could produce regarding rust or other software topics on this channel again please support the channel by going to the Amazon store link and making purchases for certain essential products through that store I also recommend some electronics that I personally use like
My drone my computer parts and that kind of thing so please check out that Amazon store affiliate link thanks so much for watching and we’ll see you in the next video Take Care by
Video Keywords: Rust Programming, rust,rustlang,rust developer,rust programming,rust software,software,open source software,systems programming,data structures,rust structs,rust enums,rust coding,rust development,rustlang tutorial,rust videos,rust programming tutorial,getting started with rust,beginner with rust programming,rust concepts
-
Sale!
Wireless WIFI Repeater Extender Amplifier Booster 300Mbps
$29.99$14.99 Add to cartWireless WIFI Repeater Extender Amplifier Booster 300Mbps
Categories: Electronics, Wi-Fi Router, Wireless Wi-Fi Extender Tags: 300Mbps, 802.11N, Amplifier, Booster, Extender, mobile wi-fi booster, Remote, WIFI, Wireless, Wireless WIFI, Wireless WIFI Repeater, Wireless WIFI Repeater Extender, Wireless WIFI Repeater Extender Amplifier, Wireless WIFI Repeater Extender Amplifier Booster, Wireless WIFI Repeater Extender Amplifier Booster 300Mbps$29.99$14.99 -
Sale!
Full RGB Light Design Gaming Headset Headphones with Mic
$24.99$14.99 Add to cartFull RGB Light Design Gaming Headset Headphones with Mic
Categories: Electronics, Gaming, Gaming Headsets Tags: Design, Full, Full RGB Light Design Gaming Headset, Full RGB Light Design Gaming Headset Headphones, Full RGB Light Design Gaming Headset Headphones with Mic, Gamer, Gaming, Gaming Headset Headphones, gaming headset wireless, Headphone, Headphones, Headset, Light, Mic, Package, RGB$24.99$14.99 -
Sale!
Wireless BlueTooth Multi-Device Keyboard Mouse Combo
$39.99$19.99 Add to cartWireless BlueTooth Multi-Device Keyboard Mouse Combo
Categories: Electronics, Gaming, Gaming Keyboards, Keyboard Mouse Combos Tags: Combo, Keyboard, keyboard mouse combos, Mouse, MultiDevice, Set, WireKeyboard Mouse Combo, Wireless, Wireless BlueTooth Keyboard Mouse Combo, Wireless BlueTooth Keyboard Mouse Combos, Wireless BlueTooth Multi-Device Keyboard Mouse Combo, Wireless BlueTooth Multi-Device Keyboard Mouse Combos$39.99$19.99 -
Sale!
High Back Leather Executive Adjustable Swivel Gaming Chair with Headrest and Lumbar
$199.99$139.99 Add to cartHigh Back Leather Executive Adjustable Swivel Gaming Chair with Headrest and Lumbar
Categories: Gaming, Gaming Chairs Tags: Adjustable, Chair, computer chairs, Desk, Executive, Gaming, Girl, Headrest, High, High Back Leather Executive Adjustable Swivel Gaming Chair, High Back Leather Executive Adjustable Swivel Gaming Chair with Headrest, High Back Leather Executive Adjustable Swivel Gaming Chair with Headrest and Lumbar, High Back Leather Executive Adjustable Swivel Gaming Chairs, Leather, Lumbar, Office, Racing, Swivel$199.99$139.99 -
Sale!
Professional LED Light Wired Gaming Headphones with Noise Cancelling Microphone
$29.99$19.99 Select optionsProfessional LED Light Wired Gaming Headphones with Noise Cancelling Microphone
SKU: N/A Categories: Electronics, Gaming, Gaming Headsets Tags: Cancelling, Gaming, Gaming Headphones with Noise Cancelling Microphone, gaming headset, Headphones, Headset, LED, Light, Mic, Microphone, Noise, Professional, Professional LED Light Wired Gaming Headphones, Professional LED Light Wired Gaming Headphones with Noise Cancelling Microphone, Wired, Wired Gaming Headphones, Wired Gaming Headphones with Noise Cancelling Microphone$29.99$19.99 -
Sale!
Gaming Desk with LED Lights USB Power Outlets and Charging Ports
$349.99$249.99 Select optionsGaming Desk with LED Lights USB Power Outlets and Charging Ports
SKU: N/A Categories: Computer Desk, Gaming, Gaming Desk Tags: and Charging Ports, Charging, Desk, Desks, Gaming, gaming desk with led lights, Gaming Desks with LED Lights, Home, LED, Lights, Monitor, Office, Outlets, Port, Power, Room, Stand, USB, USB Power Outlets, White, Workstation$349.99$249.99 -
Sale!
Wired Mixed Backlit Anti-Ghosting Gaming Keyboard
$99.99$79.99 Add to cartWired Mixed Backlit Anti-Ghosting Gaming Keyboard
Categories: Electronics, Gaming, Gaming Keyboards Tags: Antighosting, Backlit, Blue, brown, Gaming, Gaming Keyboard, gaming keyboards, gaming keyboards and mouse, Keyboard, Laptop, Switch, Wired, Wired Mixed Backlit Anti-Ghosting Gaming Keyboard, Wired Mixed Backlit Anti-Ghosting Gaming Keyboards, Wired Mixed Backlit Gaming Keyboard$99.99$79.99 -
Sale!
Wireless Bluetooth 5.3 ANC Noise Cancellation Hi-Res Over the Ear Headphones Headset
$119.99$59.99 Add to cartWireless Bluetooth 5.3 ANC Noise Cancellation Hi-Res Over the Ear Headphones Headset
Categories: Electronics, Gaming, Gaming Headsets Tags: 5.3 ANC Noise Cancellation Hi-Res Over the Ear Headphones Headset, ANC, Audio, Bluetooth, Cancellation, Ear, Earphone, gaming headset, Headphones, Headset, Hi-Res Over the Ear Headphones Headset, HiRes, Noise, Wireless, Wireless Bluetooth 5.3 ANC Noise Cancellation Hi-Res Headphones, Wireless Bluetooth 5.3 ANC Noise Cancellation Hi-Res Over the Ear Headphones Headset, Wireless Bluetooth 5.3 ANC Noise Cancellation Hi-Res Over the Ear Headphones Headsets$119.99$59.99 -
Sale!
Wired Sports Gaming Headset Earbuds with Microphone
$19.99$9.99 Select optionsWired Sports Gaming Headset Earbuds with Microphone
SKU: N/A Categories: Gaming, Gaming Headsets Tags: Accessories, Earbud, Earphone, Earphones, Gaming, gaming headset with microphone, Headphones, Headset, IOS, Microphone, Sports, Wired, Wired Sports Gaming Headset Earbuds, Wired Sports Gaming Headset Earbuds with Microphone, Wired Sports Headset Earbuds$19.99$9.99 -
Sale!
150W Universal Multi USB Fast Charger 16 Port MAX Charging Station
$49.99$29.99 Add to cart150W Universal Multi USB Fast Charger 16 Port MAX Charging Station
Categories: Charging Stations, Electronics Tags: 150W, 150W Charging Station, 150W Universal Multi USB Charging Station, 150W Universal Multi USB Fast Charger 16 Port MAX Charging Station, 150W Universal Multi USB Fast Charger 16 Port MAX Charging Stations, 150W Universal Multi USB MAX Charging Station, 16 Port MAX Charging Station, 3.5A, Charger, Charging, Fast, laptop charging stations, Max, Multi, Port, Stand, Station, Universal, USB$49.99$29.99
Nice one. Could you make a video about a multi file/module project? Proper imports etc
I love this channel, thanks a lot Trevor
I guess more idiomatic way is format macro
Great video. I‘d love to watch a video about integration tests,
Hey Trevor, please make a video on error reporting library named "miette"
btw really appreciate your contents👌. They have always been so much helpful for me 😇
Thanks for the video, really great explanation!
You're killing with these videos👌🏽
Keep them coming and let's hope the algorithm blesses you🙌🏽
Thank you so much.
🚨📦 Help support this channel — shop through my Amazon storefront!
⬇⬇⬇
https://www.amazon.com/shop/trevorsullivan
⬆⬆⬆