You're Testing Your Angular Code Wrong (Probably)

Поделиться
HTML-код
  • Опубликовано: 13 окт 2024
  • $200 off Discount Link:
    ti.to/ng-conf/...
    Are you wondering why your unit tests are taking too long to execute? Want to improve the performance and simplify your unit tests? Joe Eames has a tip to simplify your test, increase the speed, and get you unit testing like a pro
    ng-conf is a three-day Angular conference focused on delivering the highest quality training in the Angular JavaScript framework. 1500+ developers from across the globe converge on Salt Lake City, UT every year to attend talks and workshops by the Angular team and community experts.
    Follow us on twitter / ngconf
    Official Website: www.ng-conf.org/

Комментарии • 73

  • @LarsGyrupBrinkNielsen
    @LarsGyrupBrinkNielsen 4 года назад +32

    I think the key takeaway is this: "Don't put complex logic in your component templates". Extract that logic to software artifacts that are easier and faster to test.

  • @privettoli
    @privettoli 4 года назад +47

    By avoiding to test 90% of the component (template, injections, lifecycle) you're not simplifying, you're creating two patterns in your source code. 2 patterns over 1 pattern != simple. Claiming that everyone else who's using TestBed is doing it wrong is… well… misleading. If you have a preference in style of testing, keep it subjective, that's just your preference, not best practice.

    • @dvabuzyarov
      @dvabuzyarov 4 года назад +5

      Nothing prevent you from testing components in such way. The only thing that is not testable is templates.

    • @amirovuz
      @amirovuz 4 года назад

      @@dvabuzyarov Just great answer :)

    • @JoeEames
      @JoeEames 4 года назад +5

      it's not a preferential style. It's an often unnecessary overhead. and you can test injections, lifecycle, etc using this method. the only thing you can't test is the template. Only if you understand that can you decide how to test your components most effectively.

    • @mjerez6029
      @mjerez6029 4 года назад +4

      I totally agree with the video, we should remove most of the logic from the templates and only test component.
      So happy I saw this video just before starting a new project. 😁🏆✌️
      I would totally call this a best practice.

  • @dachd
    @dachd 4 года назад +24

    You don't have a problem when you are not having any tests at all. :D

  • @rossanmol
    @rossanmol 4 года назад +17

    Not sure if this is useful in most cases, usually you would need to test the template, and inject services. Testbed does it all for you.

    • @JoeEames
      @JoeEames 4 года назад +6

      you can inject services. and if most of your tests hit the template, then there's a decent chance you're overtesting. as a ridiculous blanket statement, probably 10% of all tests need to test the template. It'll really vary a lot from project to project and coponent to component, but it's at least a reasonable starting point.

    • @tmckearn
      @tmckearn 4 года назад +2

      You don't need the Angular framework to pass something to the constructor. Also, you should be mocking any services injected anyway, or you're not doing unit tests

    • @JoeEames
      @JoeEames 4 года назад

      @@tmckearn exactly.

    • @JentaroYusong
      @JentaroYusong 4 года назад +4

      I think that is a bold statement. The user does not see the component, he sees the template. That is why we actually test the template on nearly all components and thus use the TestBed. However, we try to keep most of our components "dump", such that the component basically is just given some data to display. Most of the logic, such as handling streams of data, we put into Services which really don't need the TestBed for testing. Also with Ivy the run times of TestBed based tests have been reduced significantly. Simply not testing the template is a bad idea imho. A component presents some UI so just testing the inner works of it - the typescript code - seems not to be enough. Sure there are E2E tests but I prefer to fail fast.

  • @Nick0n
    @Nick0n 4 года назад +49

    I don't trust ppl who use white IDE theme...

  • @McQuinTrix
    @McQuinTrix Год назад

    Appropriate title would be: You're UNIT testing your angular code wrong way. Love the video btw.

  • @AnkitTannaVlogs
    @AnkitTannaVlogs 4 года назад +4

    I love the way you explained the importance of NOT using TestBed everywhere. But it would be a very complex task with all the mocking and minimum 3 dependencies in the constructor to be mocked in the component.

  • @debajitbiswas3104
    @debajitbiswas3104 4 года назад +2

    This is the simpliest test you have written, when complex cases arises..you need before each, after each all those thing

  • @dvabuzyarov
    @dvabuzyarov 4 года назад +3

    I am using this approach for more then 3 years at the moments. I have started with angular 1 and keep doing it with angular 9. Specially for this I ported moq lib to typescript and added a function that automatically mock all dependencies of tested unit with this lib.

  • @dvabuzyarov
    @dvabuzyarov 4 года назад +5

    On one of mine project I have 470 unit tests and it takes 0.452 sec to run them all. They covers all services, components, pipes and etc on the project.

    • @asciidiego
      @asciidiego 4 года назад +1

      You mean, with the TestBed?

    • @dvabuzyarov
      @dvabuzyarov 4 года назад +2

      @@asciidiego I am not using TestBed. Just create a static injector with all dependencies and start all unit test in nodejs environment. The only things that are not covered are html pages, but I am trying to keep them simple and put all logic in the behind code.

    • @Acid31337
      @Acid31337 4 года назад

      How often found bugs were catched by these tests?

    • @mjerez6029
      @mjerez6029 4 года назад

      @@Acid31337 that could be said for any unit test, testing templates or not.

  • @DennisKrger
    @DennisKrger 4 года назад +13

    A big problem with this: your template isn't checked anymore. Something expecting a value to be set that isn't, will be completely ignored.

    • @JoeEames
      @JoeEames 4 года назад +8

      Only when you need to test the template. when that is important, then test it. you can still write testbed tests when you want. >90% of all tests written using the testbed don't need the testbed. it's unnecessary overhead.

    • @DennisKrger
      @DennisKrger 4 года назад +4

      @@JoeEamesHonestly, my tests usually hits template problems rather than backing class problems. I'd be very wary of not testing the templates unless they're 100% dumb.
      Sure, many components are that dumb, but in those cases, the backing class is usually also just inputs, and then there is no logic to test at all.

    • @DennisKrger
      @DennisKrger 4 года назад +3

      ... I must also admit, though, that my most common mistake is forgetting to add a dependency to the testing module (though that has become somewhat better after services could just be declared as belonging to the root module). Fixing those is certainly time spent without adding any other value than getting the damn tests to work.

    • @JoeEames
      @JoeEames 4 года назад

      @@DennisKrger so true

    • @JoeEames
      @JoeEames 4 года назад +1

      @@DennisKrger your experience is vastly different than mine. template problems account for only a couple percent of problems my typical applications have (with some localized exceptions, such as custom widgets). Not saying that you are doing this, but in general, if you're putting complex logic in the template, then you should consider pushing it into the component instead. that's not ALWAYS possible, but it's a good goal. Then deal with the exceptions as they come up.

  • @BillMoman
    @BillMoman 3 месяца назад

    This is good information which I already knew that I could do tests this way. However, most tests have at least 1 service injected into the component and probably many more. If you are writing it the way you said, wouldn't you have to mock out the service each time and then add that to the constructor when instantiating the component. new Component(mockService1, mockService2, etc.) which seems like you would be writing a lot more code using it your way. Shouldn't you keep the beforeEach(() ={}); part (without the async) to do all that code one time since it will need to before run each test anyways. I do get your point as I am having a hard time explaining to fellow developers how this all works.

  • @aaronscribner
    @aaronscribner 4 года назад +5

    This is a comical case of unit testing PoC code only. Have fun writing your mock injection code for every test your write as well.
    And "performance" for a unit test. It is an automated process that runs in the background.

    • @adisurd
      @adisurd 4 года назад +2

      That performance, if I understand correctly, impacts the time it takes to get the complete feedback in your pipelines before the code can be merged / deployed. Faster is better

  • @pradeepvig9880
    @pradeepvig9880 4 года назад +4

    What about testing a component in isolation with Dependency Injection?

  • @tranhuuthu991990
    @tranhuuthu991990 3 года назад +1

    this is correct when component is super simple and almost has not logic at all. In fact, almost components are much more complicated and that’s when testbed is needed.

  • @ChihabOtmani
    @ChihabOtmani 3 года назад

    I agree, we're not supposed to be testing that *ngIf, ngFor and ngModel... are behaving correctly, those are Angular core directives that Google and the community have already spent time and money testing. The only templates that we would want to test are maybe the ones having some logic that for some reason we "could not" put in the component class or abstract out to pipes, directives, services which are tested independently.

  • @leo11877
    @leo11877 4 года назад +5

    Please do more videos on this with testing components with async and change detection etc.

  • @mikebell3579
    @mikebell3579 2 года назад

    Wow!!! Thanks for this tip. Been using Angular for years and am always surprised at how much of Angular is just JS.

  • @vikasnigam9646
    @vikasnigam9646 3 года назад

    Excellent Tip. Much appreciated sir.. Please can you also show an example of performance difference with & without using testBed?

  • @ngSamurai
    @ngSamurai 4 года назад +1

    Thanks for nice tricks. Can you create more videos about e2e testing? Please!

  • @orlovskyconsultinggbr2849
    @orlovskyconsultinggbr2849 4 года назад

    Somehow i knew this is right approach, we need to test the logic of our applications, the interaction via templates must be tested with external tools like Robot Framework or Puppeteer or Seliniium. This is great now i just need to clean and refactor my tests! Thanks!

  • @robertkylethomas173
    @robertkylethomas173 4 года назад +3

    A bit bold you to assume I'm testing in the first place...

  • @balintcsaszar6831
    @balintcsaszar6831 4 года назад +1

    True this is much faster but I have to write more tests with this pattern (with ignoring template totally) so I have to create about 1000 unit tests instead of 150-200...This is good for example React components where we use only a library, but Angular thinks we use components where this approach is not appropriate. This is a good testing method, for example, simple @Pipe, @Injectable, helper class testing, but nothing more.

  • @dvabuzyarov
    @dvabuzyarov 4 года назад

    I’ve made npm package for such style unit testing: ng-auto-moq

  • @KostiantynVesna
    @KostiantynVesna 3 года назад

    7:40 lol 😆 "a minor drawback - you cannot test the templates"

  • @darylsmith5024
    @darylsmith5024 4 года назад +2

    Just to add on to these comments - this approach really only works in the most basic use cases, when there in are no dependencies, which in most real life scenarios almost never happens. The reason developers choose frameworks like Angular in the first place, rather than vanilla JavaScript, is to deal with the challenges of complex single-page applications. The presenter in this video does have a point that the Angular test framework does contain a lot of 'moving parts', however these tools are necessary to provide proper testing support for applications with that level of complexity.

    • @JoeEames
      @JoeEames 4 года назад +2

      this method works just fine for any number of dependencies, it just wasn't shown how to do that. it's not a course on unit testing, it's a video on the problems of the testbed. And your comment is actually a good validation of the problem: you are shown how to do it with the testbed, but not without the testbed, so you assume it can only be done with the testbed and all its overhead, and that's not true.

  • @LarsRyeJeppesen
    @LarsRyeJeppesen 4 года назад

    What about private properties?

  • @SelimAbidin
    @SelimAbidin 4 года назад +4

    I would say, this is a good video that shows components are just classes but somehow I am thinking this way of testing is a bit misleading. Tests that generated by Angular-CLI is prepared for the worst scenario. Modules, Components are more compicated than this. My humble suggestion is, go with Angular's default test logic.

  • @Exejutables
    @Exejutables 4 года назад +8

    I think this is not useful, in a real escenario you need to inject services, so you need to start to instanciate services in the correct order to inject it. The only scenario where i see this useful is if you don't inject services.

    • @JoeEames
      @JoeEames 4 года назад +5

      i guess I need to do more videos. you don't need the testbed to inject services. you can do that yourself. and save tons of complexity and performance. Again, the problem is that people aren't looking at their component and realizing that it's just javascript. here's a hint: let cmp = new MyComponent(myMockService) OR let cmp = new MyComponent(myRealService) - depending on if you want to use a mock service or not. FYI Services are also just javascript. You can create instances of those as well.

    • @eus9
      @eus9 4 года назад

      You probably don't want to be running tests and injecting real instances of your services. I can recommend ts-mockito for mocking them out, it works great and helps testing a lot!

    • @tmckearn
      @tmckearn 4 года назад +1

      You are perfectly capable of passing mocked services to the constructor. If you're not mocking the services, you're doing unit tests wrong

    • @ThePerrocraft
      @ThePerrocraft Год назад

      "I think this is not useful.."::::3 seconds later::::: "The only..... I see this useful".

  • @thatchipmunksings
    @thatchipmunksings 4 года назад +2

    Yea what about super nested DIs? Are you planning on instancing 15 classes inside each constructor? This is quite stupid

    • @BillMoman
      @BillMoman 3 месяца назад

      I wouldn't call it "stupid". It's a different way to do it and while you have the same question as me, I want to see if they respond.

  • @cedrics7374
    @cedrics7374 4 года назад

    Good way to do unit tests. He clearly said there is a difference between unit testing and integration test. Now for components with heavy logic (which due to separation of concern is best put inside the component, not the template) this is a good way to test. But integration tests will also be necessary, unless you want to do it manually each release 🙂. Thank you for the video!

  • @vicky2118
    @vicky2118 2 года назад

    I found this useful only for the utility services. It may ne faster for the components but I don’t find this very useful.

  • @MahmutGundogdu
    @MahmutGundogdu 4 года назад +2

    I am interested about "What if there is a child component? "

  • @paulhax
    @paulhax 3 года назад

    Where he gets to the point 4:45

  • @JonathanYee
    @JonathanYee 3 года назад

    I disagree with this way of testing. I do agree if it is just a method on the class you're testing. Lots of comments state "yeah you don't need to test ngIfs, form control directives etc". I don't think we are testing those directives. It's the same as saying "yeah, don't test your if statements because if statements are proven to work".
    What we are actually testing is how we use ngIfs, formControlName, etc. Making sure we are using it correctly. Your template is part of your code as much as the controller.
    Angular still has MVVM framework, and we need to test that we are using it correctly.
    What if you forgot to bind an ngModel or your ngIf has the wrong expression.
    What i'm saying is don't neglect your template, it has code as much as your controller does. Test it as a whole.

  • @ChaimMosheStern
    @ChaimMosheStern 4 года назад +2

    All good until you have DI

  • @pluraltest9242
    @pluraltest9242 3 года назад

    fantastic testing a basic component; no dependency (services, childComponents, forms groups) except in real world components are way more complex might as well get rid of angular and just use simple vanilla js

  • @dromar853
    @dromar853 4 года назад

    Video starts at 2:11