How To Write Unit Tests For Existing Python Code // Part 2 of 2

แชร์
ฝัง
  • เผยแพร่เมื่อ 21 ก.ค. 2024
  • This video is part 2 of covering a practical example of adding unit tests to existing code. In the first part, I added tests while not changing the original code. In this part, I show you how refactoring the code makes testing it way easier while improving the design at the same time. I also share a few tips on how to write better unit tests.
    Part 1 of this series: • How To Write Unit Test... .
    The code I worked on in this episode is available here: github.com/ArjanCodes/2022-te....
    💡 Get my FREE 7-step guide to help you consistently design great software: arjancodes.com/designguide.
    💻 ArjanCodes Blog: www.arjancodes.com/blog
    🎓 Courses:
    The Software Designer Mindset: www.arjancodes.com/mindset
    The Software Designer Mindset Team Packages: www.arjancodes.com/sas
    The Software Architect Mindset: Pre-register now! www.arjancodes.com/architect
    Next Level Python: Become a Python Expert: www.arjancodes.com/next-level...
    The 30-Day Design Challenge: www.arjancodes.com/30ddc
    🛒 GEAR & RECOMMENDED BOOKS: kit.co/arjancodes.
    👍 If you enjoyed this content, give this video a like. If you want to watch more of my upcoming videos, consider subscribing to my channel!
    💬 Discord: discord.arjan.codes
    🐦Twitter: / arjancodes
    🌍LinkedIn: / arjancodes
    🕵Facebook: / arjancodes
    👀 Code reviewers:
    - Yoriz
    - Ryan Laursen
    - Sybren A. Stüvel
    - Dale Hagglund
    🎥 Video edited by Mark Bacskai: / bacskaimark
    🔖 Chapters:
    0:00 Intro
    0:44 Recap and analysis
    1:58 Add dependency injection to pay_order
    3:50 Creating a payment processor mock
    6:11 Removing input patching
    9:24 Using a fixture for the credit card
    11:43 Removing hardcoded dates from the unit tests
    12:50 Turning luhn_checksum into a function
    14:00 Removing the hardcoded API key from the unit tests
    15:44 Final thoughts
    #arjancodes #softwaredesign #python
    DISCLAIMER - The links in this description might be affiliate links. If you purchase a product or service through one of those links, I may receive a small commission. There is no additional charge to you. Thanks for supporting my channel so I can continue to provide you with free content each week!

ความคิดเห็น • 108

  • @ArjanCodes
    @ArjanCodes  9 หลายเดือนก่อน

    💡 Get my FREE 7-step guide to help you consistently design great software: arjancodes.com/designguide.

  • @maephisto
    @maephisto 2 ปีที่แล้ว +82

    I really admire the way you explain all these concepts. Even the quality of the video itself should not be underestimated: from the way you zoom the source code to the transitions from VS Code to yourself, it is really clear to me how much time and passion you put into this.

  • @jambosuss
    @jambosuss 2 ปีที่แล้ว +3

    This was excellent! Thanks for this, I think i'll be watching both videos many times and studying your refactored code so I can properly implement unit tests into my own projects

  • @naoraspir4896
    @naoraspir4896 ปีที่แล้ว

    You are BRILLIANT , thank you for the 2 part videos!

  • @XxNGameCubexX
    @XxNGameCubexX ปีที่แล้ว +4

    Phenomenal video about software testing, in python and in general. Also, an amazing demonstration of how unit testing can improve your code design. Subscribed!

  • @nickeldan
    @nickeldan 2 ปีที่แล้ว +13

    Great series on testing! I would love it if you would do a video or two going through the deeper features of pytest.

    • @kevinlao3690
      @kevinlao3690 2 ปีที่แล้ว

      Same here! I would like to see Arjan delve further into unit testing even more

  • @Pawl0solidus
    @Pawl0solidus ปีที่แล้ว +1

    Amazing video! The last part about env variables was really great because I needed it for a long time and was only defining env variables in terminal using export. Thank you very much for your help!

    • @ArjanCodes
      @ArjanCodes  ปีที่แล้ว +1

      Thanks so much Paulo, glad it was helpful!

  • @sparrowhawkguitarboy
    @sparrowhawkguitarboy 2 ปีที่แล้ว

    Amazing video. So much to take away and put into practice in my current projects. Thank you very much. I’ve watched several videos about TDD, and this if by far the most useful one, I’ve spent my time watching.
    Thank you very much!

    • @ArjanCodes
      @ArjanCodes  2 ปีที่แล้ว

      Thanks, happy that it’s helpful to you!

  • @neoluis2003
    @neoluis2003 ปีที่แล้ว +1

    Awesome! Invaluable learning resource. Thank you Arjan!!!

    • @ArjanCodes
      @ArjanCodes  ปีที่แล้ว

      Glad you liked it!

  • @roffel06
    @roffel06 6 หลายเดือนก่อน

    This two-parter is a great tutorial. Thanks for talking the time and effort to provide us with this content. It's really high quality.
    I'll have to rewatch the second video another time. Around the 8:00 minute mark I had a light bulb moment how I can turn one of my helper functions into a class and instantiate the object as needed. Not only will this improved my unit test, this was actually a helper function with important functionality that I may change depending on the business need. I can see how i may define different classes based on different use cases. Thanks for that.
    The video after the 8:00 minute mark was too quick and too dense for me to follow. I'll have to sit down and rewatch what you actually did there. I know this was originally intended as one video but i think you could have spread out the content over 4 videos easily, essentially adding 2 separate videos about refactoring your code. I would have watched those, too! 😂

  • @Formulka
    @Formulka 2 ปีที่แล้ว

    This is an excellent example, I would just stress how important is to keep in mind the actual functionality of the software, as presented the tests all pass but the main function includes original and non-functional call to pay_order that is missing arguments.

  • @dnlgrhm
    @dnlgrhm 8 หลายเดือนก่อน

    As usual, wonderful video and much appreciated!

    • @ArjanCodes
      @ArjanCodes  8 หลายเดือนก่อน

      Thank you, glad you enjoyed the content!

  • @lucasventura2407
    @lucasventura2407 ปีที่แล้ว

    Great Video! Wonderful way to explain, it helped me a lot!

    • @ArjanCodes
      @ArjanCodes  ปีที่แล้ว

      Thank you Lucas, glad you liked the video and it was helpful!

  • @mutsukira
    @mutsukira ปีที่แล้ว

    I really enjoy watching your great videos. Thank you.

    • @ArjanCodes
      @ArjanCodes  ปีที่แล้ว

      Thanks Abdelkarim, happy you’re enjoying the content!

  • @marconeramos1194
    @marconeramos1194 4 หลายเดือนก่อน

    Great content! Thank's a lot.

    • @ArjanCodes
      @ArjanCodes  4 หลายเดือนก่อน

      Thank you so much!

  • @BhaktiiKiShaktii
    @BhaktiiKiShaktii 4 หลายเดือนก่อน

    I am getting deeper understanding about all the core concepts of python for the software development, Great ability to teach complex logic with very ease, Thanks 🙏🏻

    • @ArjanCodes
      @ArjanCodes  4 หลายเดือนก่อน

      Glad to hear the content is helpful!

    • @BhaktiiKiShaktii
      @BhaktiiKiShaktii 4 หลายเดือนก่อน

      @@ArjanCodes extensively helpful, in our project we are moving forward with the SOLID principle and you videos helps me to understand everything related it❤️, Thanks

  • @mykolasdudutis5319
    @mykolasdudutis5319 27 วันที่ผ่านมา +2

    I'm curious about the test cases for payment.py. Shouldn't we test if the payment processor charge method was called when testing for paying the order? Since "test_pay_order" would pass even if we remove line 17 "payment_processor.charge(card, amount=order.total)" in payment.py. Similarly, shouldn't we test if the order status wasn't changed if ValueError was raised?

  • @younesveisi
    @younesveisi 2 ปีที่แล้ว

    Hi. I want to say that I really got a lot more information and views about testing and software, and I was able to program with a better and more accurate view through the 7 steps you mentioned for software design.
    But I have a request: if it is possible for you to extend this project to "bdd in Python" so that we can make more use of this knowledge
    Thank you very much, Younes

  • @kpuano
    @kpuano 2 ปีที่แล้ว +5

    I understand how dependency injection (removing the responsability of creating the dependent objects inside a function/method) makes the tests easier, since it allows passing mocks or stubs directly instead of monkey patching the actual implementation. However, the objects creation was moved to the main function, since they have to be created somewhere. Shouldn't we test it? Would that be an integration test? How does it differ from the unit tests? I always struggle with this because I still end up having to monkeypatch stuff to test the complete flow.

    • @garrywreck4291
      @garrywreck4291 2 ปีที่แล้ว +3

      Usually, you don't test "main" at all because you should keep it super simple. But you could add a few integration tests if you still think your "main" is not simple enough ;)

    • @vikingthedude
      @vikingthedude 2 ปีที่แล้ว +1

      I think the main function here would be what's called the "composition root". Its job is supposed to be the place where you "wire up" your app's dependency tree, so the code within it should as simple as possible. This usually means its not worth testing. But it depends on your specific situation

    • @apoca1ypse1
      @apoca1ypse1 2 ปีที่แล้ว +2

      This is also something I don't understand. Most applications involve the use of many side effects. Moving all side effects to a main function and not testing them does not seem like a realistic solution. Are there any good resources out there that tackle this question?

    • @vikingthedude
      @vikingthedude 2 ปีที่แล้ว +2

      @@apoca1ypse1 to unit test side effects, you don’t actually test the effects themselves. You just test to make sure that the side effect function was called correctly. You mock the side effect function and run assertions like “mock.wasCalledWithArguments(expected)”

    • @apoca1ypse1
      @apoca1ypse1 2 ปีที่แล้ว +1

      @@vikingthedude I understand that you can mock side effects to test your code. Dependency injection looks to me like a method of moving where you mock rather than how to avoid mocking all together. If my understanding is correct then how do you decide where the best place for mocking is?

  • @rayu526
    @rayu526 2 ปีที่แล้ว +3

    Great video! I'm just binge watching all of them :)
    Note: I would consider inverting also dependency to datetime.now(). Thanks to that you can mock in your tests what day is today and test i.e. how PaymentProcessor would behave on Feb 29th or Dec 31st

  • @owenlu6527
    @owenlu6527 ปีที่แล้ว

    This man is a magician

  • @nateriver8261
    @nateriver8261 2 ปีที่แล้ว

    Hey! Can you make a video about proxy and decorator patterns?

  • @AdoniasAlbuquerqueEng
    @AdoniasAlbuquerqueEng 11 หลายเดือนก่อน

    Very good and helpful, thanks a lot
    a little feedback, its kind harder to focus on the code if you zooming on your face like that, would be better to have the code on the screen all the time.

  • @MariusOdobasa
    @MariusOdobasa ปีที่แล้ว

    You are great!

  • @abdelghafourfid8216
    @abdelghafourfid8216 2 ปีที่แล้ว +1

    Great video as always,
    a side note is that I always wonder what are the shortcuts you keep using on your videos when coding, it really makes your coding looks very smooth and easy, I hope you could cover that in a future video

    • @briancline0
      @briancline0 2 ปีที่แล้ว

      They sound almost identical to vim shortcuts/keybinds (especially copy/paste for instance -- sounds like he's using the `yy` keybind to copy a line, then `p` to paste it after current line). Most IDEs with a plugin ecosystem have a vim keybindings plugin, so give that a shot. They can take a while to learn, but once you get used to them they really help do things quickly.

  • @curtking70
    @curtking70 2 ปีที่แล้ว

    Thanks!

    • @ArjanCodes
      @ArjanCodes  2 ปีที่แล้ว

      Thanks so much Curt, glad you liked it!

  • @dirkvandam9745
    @dirkvandam9745 2 ปีที่แล้ว

    @arjan, thanks for replying to my previous comment, appreciate it and using it successfully. I had another question, if you have the time. Again on the subject of unit tests :) Described simply I have a class that contains a data cube (3-D) that contains methods used for plotting different 2-D slices of the cube (index and axis, and also a scrollable interactive window). I was wondering if there is an appropriate way to pytest figures/axes objects made by matplotlib. Would I have to monkey patch it / is there a good / standard way of asserting proper figures/axes objects?

  • @mikeciul8599
    @mikeciul8599 2 ปีที่แล้ว +7

    I asked this last week, but I still want to know - what are your thoughts on unittest vs pytest? Who here uses which one, and why do you prefer it to the other? I use both together sometimes, but I worry that this could lead to trouble. What do you think?

    • @garrywreck4291
      @garrywreck4291 2 ปีที่แล้ว +4

      I'll share my experience, maybe it will be useful. I started with pytest but then switched to unittest because grouping related things under a TestCase seemed very nice and mainainable. But I still used "assert" and "pytest.raises" because they are prettier ;) but then I discovered that when a project grows, TestCases become in some way noisy. Also, you will always find out that, for example, "self" is not used (i.e. it could be a simple function). The next step for me was to return back to plain functions. I replaced TestCases by more complex packages/modules hiararchy and in the end it seems much better. About pytest fixtures... I tried them hard but in the end I abandoned it. I find them not flexible enough because they don't accept parameters (ofc you can make them to accept parameters but it looks hacky). So I use helper functions usually stored under tests/utils package. The only thing I use fixtures for is setup/teardown. And almost always those are fixtures with "session" scope and autouse=True located under conftest py. For example, loading of dummy SQL to a database.

    • @sulfur32066
      @sulfur32066 2 ปีที่แล้ว +1

      Pytest is much bigger, have more features to use, and good solution as well, has good documentation and support. Unittest Library is kind of local or small story and pytest is a complete solution for really big and complex things

    • @sulfur32066
      @sulfur32066 2 ปีที่แล้ว +1

      And of course, even into pytest documentation you could find some things from unittest like patch for example

    • @mikeciul8599
      @mikeciul8599 2 ปีที่แล้ว +1

      @@sulfur32066 That makes me think I'm missing out on a lot of what pytest can do. I like unittest `self.assertEqual`, `assertIn`, `assertRaises`, and 'assertLogs`... I'm not sure I know the idiomatic way to do all of those things in pytest, and I'm not sure what kind of context it gives when assertions fail - pytest users, do you ever test for log statements? Is there a pytest way?
      I also like using `Mock.assert_called_with`. Since I started watching this channel, I've been replacing patching with dependency injection. But I still want to assert that the right calls were made, so I'm still using unittest.Mock... what are your thoughts?

    • @sulfur32066
      @sulfur32066 2 ปีที่แล้ว +1

      @@mikeciul8599 for such cases I personally prefer to use patch from unittest.mock inside pytests, this method allows you to patch specific method call and return whatever you want as a result and you could use built-in things like .call_count, .call_args etc on patched method

  • @mouttiedje4795
    @mouttiedje4795 2 ปีที่แล้ว

    What would be the argument of using pytest vs unittest?

  • @KLM1107
    @KLM1107 2 ปีที่แล้ว +1

    Really informative video! One thing I do for sensitive variables like API keys is to use the keyring module, that way you can avoid any extra files or plaintext storage of secrets.
    Another thought, would it not make sense to validate the credit card number as part of the dataclass?

    • @aflous
      @aflous 2 ปีที่แล้ว

      Totally makes sense to me, you can have a property checking the card validity inside the dataclass

  • @deemon710
    @deemon710 ปีที่แล้ว

    Does anyone know how to setup one's environment in WSL so pytest recognizes python 3.10 syntax such as the new match / case stuff? I'm having a heck of a time not finding a solution when I'm pretty sure one exists.

  • @evolagenda
    @evolagenda 2 ปีที่แล้ว

    how do you get away with pay_order(order) when the function expects pay_order to have 2 positional args order and processor. I tried replicating this pattern in my code and the tests work because I can mock a processor or some function and pass it like pay_order(order, ProccessorMock()) but when I try to run the real code it fails saying I didn't pass a processor. Does that mean you have to import the real Processor function and pass that whenever you want to use pay_order()? So you only get rid of the import dependency for the test, the live code would still need the import?

  • @mrswats
    @mrswats 2 ปีที่แล้ว +4

    For dates one package I love is freezegun (and there is the appropriate pytest plugin for it as well) that it allows you to monkeypatch the today date so you do not ever have to worry about dates anymore.
    And, another thing, I would argue that hardcoding API keys for testing is fine (given that they are not real api keys) and that you mock the requests to the API itself so you also solve a whole lot of problems with that part specifically. But, with good design, it should be possible to sort that out easily.

    • @ArjanCodes
      @ArjanCodes  2 ปีที่แล้ว +2

      Thanks for the tip! And indeed, you won't always need an API key directly in the testing code (I did this in the example as well, using the PaymentProcessorMock).

    • @mrswats
      @mrswats 2 ปีที่แล้ว

      @@ArjanCodes yeah, yeah, for the video makes sense to do so

    • @mikeciul8599
      @mikeciul8599 2 ปีที่แล้ว +1

      I love freezegun, thanks for posting!

  • @NZ255
    @NZ255 2 ปีที่แล้ว +2

    Would the validate card and luhn functions be better placed in the CreditCard class? As they’re credit card specific?
    Thanks very much for the great videos!

    • @ArjanCodes
      @ArjanCodes  2 ปีที่แล้ว +2

      Yes, good suggestion, that makes more sense than leaving it with the payment processor as it is now.

  • @dirkvandam9745
    @dirkvandam9745 2 ปีที่แล้ว +2

    @arjan love your videos they are both informative and fun and have helped me a lot. I’m currently working on writing unit tests and am using pytest. I was wondering what the advantage was of using a pytest fixture as opposed to just defining a constant with the object at the top of the unit test script?

    • @ArjanCodes
      @ArjanCodes  2 ปีที่แล้ว +8

      Hi Dirk, glad to hear you like the videos! If you use a fixture, a fresh, new object is created for each test. This is better than using a constant, which creates an object only once, when loading the script. You don't want that one test accidentally influences another test by changing the object that both tests rely on.

    •  2 ปีที่แล้ว

      Excellent question Dirk, I was wondering the exact same thing. Thanks for the answer Arjan!

    • @Shivnaren
      @Shivnaren 2 ปีที่แล้ว

      @@ArjanCodes Thanks a lot for the videos, Arjan-I've been learning tons.
      One thing I like to do sometimes is define a _function_ that returns a fresh object--almost like a constructor.
      Similar to the current setup in the video, just without the decorator.
      Works just as well as a pytest fixture, but is a bit more explicit (in terms of linting support), I feel.

  • @AvihayBar
    @AvihayBar 2 ปีที่แล้ว

    Love your content! I know it's off topic, but I like you better in a T-shirt. you just feel more comfortable that way. (congrats on the new studio, btw!)

    • @ArjanCodes
      @ArjanCodes  2 ปีที่แล้ว +1

      Haha, yes I went fancy for the first batch of videos in my new studio. I'm going back to t-shirts and hoodies for the next batch ;).

  • @olivierserve152
    @olivierserve152 2 ปีที่แล้ว

    Excellent video as usual ! A little thought : Sometimes I feel like dataclasses without any methods could really be named tuples. That seems especially the case for the creditCard class, as it would be realistic that the values (number, month, year) should never change once the card is initialized.

    • @DeathBean89
      @DeathBean89 2 ปีที่แล้ว

      You're right, the CreditCard class here could just be a named tuple. There isn't really much difference between a named tuple and a basic dataclass in practice, since both are meant to be simple wrappers for data. I personally prefer the dataclass approach, as I have always just felt that tuples are objects that were poorly defined.
      Plus, if you use a dataclass then you can easily add things like equality checking and ordering, without needing to define a separate function to handle that behavior correctly. You can just add the appropriate dunder methods to the class so it's all in the same spot.

    • @olivierserve152
      @olivierserve152 2 ปีที่แล้ว

      Hi,@@DeathBean89 thanks for confirming the feeling. I think I understand your point of view. I guess that choosing data class over named tuple allows more flexibility in later developments and if required it is always possible to have it frozen (and make it hashable).

  • @ting7949
    @ting7949 ปีที่แล้ว

    It’s amazing…

  • @BelgranoK
    @BelgranoK 2 ปีที่แล้ว

    Great!
    I worked a lot with dates and timestamps. I suggest to inject time to functions instead of give them the responsability of getting the right time data. Thats makes code more testable and eiser to reuse.

    • @ArjanCodes
      @ArjanCodes  2 ปีที่แล้ว +1

      Good suggestion! You could use a fixture for this that delivers the current date/time. Or do you use a separate package for this?

    • @BelgranoK
      @BelgranoK 2 ปีที่แล้ว

      @@ArjanCodes I do not use fixture because function depends heavily on current date/time. It is important to test the behavior for limit values like last day of the month, last day of the year, leap years, etc. In some cases we implemented a function to provide the current time in order to ease mocking for integration tests.

  • @nraw_
    @nraw_ หลายเดือนก่อน

    You mentioned in the previous video that you're testing your own code rather than 3rd party APIs. But in general, I kind of need to do both? There are times where I want to abstract that away and there are times where I'd like to have it. What's the best way to represent this with code?

  • @Phaust94
    @Phaust94 2 ปีที่แล้ว

    Great stuff man, always helpful.
    What's up with those 82% coverage at 16:51 tho?

    • @oleandreasramsdal5619
      @oleandreasramsdal5619 2 ปีที่แล้ว

      IIRC there were two test-methods with same name in the last video.

    • @DeathBean89
      @DeathBean89 2 ปีที่แล้ว

      If you go back to Part 1 @9:30, you can see that he has two test methods with the same name in test_order.py. The one that is defined first is not being run, since the second one is overwriting it in the namespace. As a result, 3 lines of test code are not being run and are counted as misses in the report.

  • @user-we2pj7un4h
    @user-we2pj7un4h 2 ปีที่แล้ว +1

    For .env you can also use python-decouple.

    • @ArjanCodes
      @ArjanCodes  2 ปีที่แล้ว +1

      Thanks for sharing that, looks nice!

  • @Shivnaren
    @Shivnaren 2 ปีที่แล้ว

    At 15:40, the line `API_KEY = os.getenv("API_KEY") or ""`
    New to me, and pretty cool.
    Is there documentation for this, or some resource explaining it?

  • @ugurozcan4886
    @ugurozcan4886 2 ปีที่แล้ว

    Hello, Arjan. Thank you for amazing video. You explained most of things about the unit testing. I like your code refactor. I want to ask a question about this video. You used dotenv library to read API_KEY. Can we use .ini file and read this file with configparser library? Which method is more generic?

    • @ArjanCodes
      @ArjanCodes  2 ปีที่แล้ว +2

      Hi Ugur, Sure, using an ini file with the key is also possible. You just have to make sure that the file is only placed in locations where it's secure. In systems deployed in the cloud, it's common practice to use environment variables for this. That's why I used a .env file in this example.

  • @MrG895
    @MrG895 2 ปีที่แล้ว +1

    For when you refactor PaymentProcessor.luhn_checksum into a module-level method, what are your thoughts in refactoring it to a staticmethod of the class instead? Arguably the method is logically related to the class and you wouldn't need to create a new PaymentProcessor object to access/test it if it is static, but I could see where having it as a module function allows for more flexibility.

    • @JGnLAU8OAWF6
      @JGnLAU8OAWF6 ปีที่แล้ว

      If anything it should be moved to CreditCard class, perhaps even as creation time validator.

  • @maga3055
    @maga3055 ปีที่แล้ว

    An even better way to take care of the date issue: Inject a datetime object into the validate_card function. Then you can create unit tests with a fake date.

  • @tanjt107
    @tanjt107 2 ปีที่แล้ว

    What about saving API keys in a separate json or yaml file?

    • @ArjanCodes
      @ArjanCodes  2 ปีที่แล้ว +1

      Sure, that would work too. The most important thing is to make sure you don't commit the file to the repository.

  • @SuperMotaba
    @SuperMotaba 2 ปีที่แล้ว

    Hey Aryan, when you create the PaymentProcessorMock class, aren’t you no longer testing the actual code? But a simplified version of the real class? If you ever change the actual class, won’t you have to change the mock class, thus defeating the purpose of having these tests?

    • @ArjanCodes
      @ArjanCodes  2 ปีที่แล้ว

      Hi Johnny, the place where I use the PaymentProcessorMock class is in the code where I test the pay_order function. So I use the mock to make testing the original code (which is the pay_order function) a lot easier. As I mention near the end of the video: it’s important to always make sure that you’re testing the right thing at the right level. It’s really easy to make the mistake where you’re testing built in Python functionality, or as you write, you’re testing mock classes and functions instead of the actual code.

  • @mikeciul8599
    @mikeciul8599 2 ปีที่แล้ว

    When I create an object to replace an injected dependency, I often call it a Fake. But I don't really know the difference between a fake and a mock. Can anyone tell me?

    • @ChrisMasto
      @ChrisMasto ปีที่แล้ว

      It depends on who you ask. I'd say most people don't care and use them interchangeably. But one way to classify them, for those who draw a distinction: mocks and stubs are two kinds of fakes: a stub is what was shown in this video, and what you're describing: a do-nothing object created to satisfy a dependency.
      Mocks, on the other hand, are used to test the other code's interaction with the object. For example, the PaymentProcessorMock here is really a stub because it doesn't contribute to testing anything. But if you had it keep track of when its charge() method is called, and at the end of the pay_order test you assert that charge() was called exactly once and with the correct arguments, then it would be functioning more like a mock.

    • @mikeciul8599
      @mikeciul8599 ปีที่แล้ว

      @@ChrisMasto Is that also called a spy?

    • @ChrisMasto
      @ChrisMasto ปีที่แล้ว

      @@mikeciul8599 I'm not familiar with that term. But a quick web search suggests that a spy is a wrapper around the original object to intercept or track its usage. Whereas a mock is more of a brand new object that fakes the behavior while keeping track of its usage.

  • @sulfur32066
    @sulfur32066 2 ปีที่แล้ว +1

    Great video! I guess using freeze_gun for datetime would be better than your trick with date, wdyt?)

    • @ArjanCodes
      @ArjanCodes  2 ปีที่แล้ว +1

      Great suggestion, that's indeed a good, generic solution to dealing with dates in tests.

  • @marcotroster8247
    @marcotroster8247 2 ปีที่แล้ว

    Hey Arjan, did you miss out on the actual use case test for "making a payment via credit card"? I'm not so sure anymore if you added such a test for validating the whole thing 🤔😅

    • @Lars16
      @Lars16 2 ปีที่แล้ว +1

      Wouldn't that be an integration test? These videos have focused on unit tests.

    • @troncooo409
      @troncooo409 2 ปีที่แล้ว +1

      Idea for a next video? How can you be sure, that the refactored code is working as intended?

    • @marcotroster8247
      @marcotroster8247 2 ปีที่แล้ว

      @@Lars16 You can basically put as much code together as you like. If you're creating larger sized components where the payment is just a small submodule, it can be a legitimate "unit test" 😂
      So I'd say don't tunnel too much on testing single classes, codefiles or functions. Rather test meaningful behavior that has a real-world use case behind it 😄
      If you're just asserting that each line is doing what you've written in your implementation, your tests will be so closely coupled to the code that refactoring will be very painful 😅

    • @marcotroster8247
      @marcotroster8247 2 ปีที่แล้ว

      @@troncooo409 Haha yeah, that's always a good starting point 😂

  • @kamilbojdo2094
    @kamilbojdo2094 2 ปีที่แล้ว +1

    I am confused. Why lots of your tests are not asserting anything? Virtually you have 100% coverage, but with no asserts you never test if your pay_order function even calls any method of payment procesor. You can delete whole code that is interacting with payment procesor from the function, and your tests will not fail.

    • @ArjanCodes
      @ArjanCodes  2 ปีที่แล้ว

      I don't understand what you mean. When I look at the tests in the repository, all of them have an assert statement in them, except for the ones where I'm checking that an action raises an error using pytest.raises (in which case adding an assert doesn't make sense). There's one test that doesn't have an assert or a pytest.raises, which is test_charge_card_valid. This one could be wrapped with a 'not pytest.raises' statement, but all the other tests seem fine to me.

    • @kamilbojdo2094
      @kamilbojdo2094 2 ปีที่แล้ว +1

      Ok. Maybe it is my fault. I looked only into the video, and on TH-cam I don't see these asserts, but on repository they are added. Anyway, issue that I mention seems still existing. You can delete line 17 from payment.py file (charging of card) and tests will still not fail, but the card will not be charged.

  • @_noirja
    @_noirja ปีที่แล้ว +2

    Do you have to be a bit careful mocking certain parts of code in your tests? Could that not lead to tests that pass without actually testing the intended functionality? I guess the developer just has to think carefully.

  • @skl9942
    @skl9942 2 ปีที่แล้ว

    Thanks!

    • @ArjanCodes
      @ArjanCodes  2 ปีที่แล้ว

      Thank you Samuel!