How do you write unit tests for Htmx?
Stack overflow isn't letting me post such a short question, so this paragraph says that I didn't see docs or a library about this.
EDIT: Specifically, I wish to unit test in Django.
There are a couple of solutions to this:
Many server side platforms offer the equivalent of rails "functional" controller tests, and those can be used to test your partial end points, depending on what platform you are using.
You can write client side javascript tests in the normal manner. The htmx test suite uses chai.js & mocha.js to create a test suite, and sinon.js to mock out the server side. If you can run the tests against your actual server, that will simplify things even more.
Broadly, for day to day unit tests, I would lean towards the first approach because it will be more stable and "functional" and then use the second approach for integration testing.
I guess you use some kind of framework. For example Django, Laravel, Ruby on Rails, ...
Just use the tools of your framework to test your http endpoints.
For e2e tests I would use Playwright. But keep in mind this rule: 80% unittests, 15% integration tests, 5% e2e tests.
I have one e2e test which checks to happy path.
And a lot of pytest-django based tests.
For forms I use this pattern: html_form_to_dict
Maybe this question gets better answers in the discord channel, since there is no clear answer.
Related
I am pretty confuse with unit and integration testing of traditional software development and web development. I have seen many different answer and explanation of it.
The Web Engineering textbook says about unit and integration testing for web application:
Unit testing: Testing on single web page as opposed to testing single function
Integration testing: Testing on flow of data from one web page to another (and linkage)
while the software engineering textbook defines unit testing and integration testing as followed.
unit testing: Testing on smallest unit
integration testing: Testing on interaction between unit or module
Hope someone can clarify to me which is the correct one.
The "web engineering" textbook is... likely wrong. That's not what those words mean to most folks.
Unit testing: testing the smallest possible bits of functionality, independently. For Java, something like the JUnit framework is used to do this. You often try to test just one class, and you may fake it's dependencies using something like Mockito, so you're really testing just one thing.
Integration Testing: testing several parts of the system together. This may be a small integration test (testing multiple classes without mocking), or something large, like making sure that your webserver is connecting to a database correctly.
End-to-End Testing: the biggest Integration test; this is basically standing up every part of your system and running scripts that look like fake users. Selenium is a tool used for this.
Upon reading Growing Object Orientated Software Guided by Tests, I learnt of test isolation and test fragility. The idea that each test should be very specific to a piece of code or functionality, and the overlap of code coverage by tests should be kept to a minimum.
The implied ideal that each change in the code should result in breaking only one test.
Avoiding spending time going through multiple broken tests to confirm that one change is the cause and if it is fixed by the test modifications.
Now this seems easy enough for unit tests, they are very isolated by their nature.
However when presented by integration tests, it seems hard to avoid having multiple tests exercising the same code paths, particularly when run in addition to the unit tests.
So my question, is what dependencies should be mocked when doing integration testing? Should anything be mocked at all? Should a single execution path be tested, and all side effects not directly relevant to this code path be mocked?
I'm toying with the idea of doing pairwise integration testing. Test one relationship between two objects, and mock everything else. Then changes in either one of these objects should have minimal impact on other integration tests, in addition to forming a complete chain of end-to-end tests by means of pairs.
Thanks for any info..
Edit: Just to clarify, I'm basically asking "How do I avoid large numbers of failing integrations tests during the normal course of development?". Which I assume is achieved by using mocks, and why I asked about what to mock.
Update: I've found a very interesting talk about Integration tests by J.B.Rainsberger, which I think answers this fairly well, if perhaps a bit controversially. The title is "Integration Tests are a Scam", so as you can guess, he does not advocate Integration Tests at all (end to end type tests). The argument being that Integration Tests will always be far below the amount needed to thoroughly test the possible interactions (due to combinatoric explosion), and may give a false confidence.
Instead he recommends what he calls Collaboration Tests and Contract Tests. It's a 90 min talk and unfortunately the whiteboard is not very clear and there aren't code examples, so i'm still getting my head around it. When I have a clear explanation I'll write it here! Unless someone else beats me to it..
Here's a brief summary of Contract Tests. Sounds like Design by Contract type assertions, which I believe could/would be implemented in a Non-Virtual Interface pattern in C++.
http://thecodewhisperer.tumblr.com/post/1325859246/in-brief-contract-tests
Integration Tests are a Scam video talk:
http://www.infoq.com/presentations/integration-tests-scam
Summary:
Integration tests are a scam. You’re probably writing 2-5% of
the integration tests you need to test thoroughly. You’re probably
duplicating unit tests all over the place. Your integration tests
probably duplicate each other all over the place. When an integration
test fails, who knows what’s broken? Learn the two-pronged attack that
solves the problem: collaboration tests and contract tests.
For integration tests you should mock the minimum amount of dependencies to get the test working, but not less :-)
Since the integration of the components in your system is obviously the thing you want to test during integration testing, you should use real implementations as much as possible. However, there are some compontents you obviously want to mock, since you don't want your integration tests to start mailing your users for instance. When you don't mock these dependencies, you obviously mock too little.
That doesn't mean btw that you shouldn't allow an integration test to send mails, but at least you want to replace the mail component with one that will only send mail to some internal test mail box.
For integration tests I lean towards mocking the service rather than the representation for example using mirage instead of a 3rd party REST API and Dumpster rather than a real SMTP server.
This means that all layers of your code are tested, but none of the 3rd parties are tested so you are free to refactor without worrying that the tests will fail.
Unit tests should have mock objects, but integration tests should have few if any mocks (otherwise what is being integrated ?) I think it's overkill to do pairwise mocking; it will lead to an explosion of tests that might each take a long time and lots of copy and paste code which will be a pain to change if requirements change or new features are added later.
I think it's fine to to not have any mocks in the integration tests. You should have everything mocked in the unit tests to know that each individual unit works as expected in isolation. The integration test tests that everything works wired together.
The discussion of Contract/Collaborator test pattern (described by JB Rainsberger in "Integration Tests are a Scam" mentioned in the question above). Relating to the question here - I interpreted his talk to mean that when you own the code for both the service side and the client side, then you should not need any integration test at all. Instead you should be able to rely on mocks which implement a contract.
The talk is a good reference for high level description of the pattern but doesn't go into detail (for me at least) about how to define or reference a contract from a collaborator.
One common example of the need for Contract/Collaborator pattern is between an API's server / client (for which you own the code of both). Here's how I've implemented it:
Define the contract:
First define the API Schema, if your API uses JSON you might consider JSONSchema. The schema definition can be considered the "Contract" of the API. (And as a side note, if you're about to do that, make sure you know about RAML or Swagger since they essentially make writing JSONSchema APIs alot easier)
Create fixtures which implement the contract:
On the server side, mock out the client requests to allow unit testing of the requests/responses. To do this you will create client request fixtures (aka mocks). Once you have your API defined, validate the fixtures against the JSONSchema to ensure that they comply. There are a host of schema validators - I currently use AJV (Javascript) and jsonschema (Python), but most languages should have an implementation.
On the client(s) side you will likely mock out the server responses to allow unit testing of the requests. Follow the same pattern as the server, validating the request and response fixtures via JSONSchema.
If both the Client and the Server are validating their fixtures against the contract, then whenever the API Contract changes, the out of date implementations on both sides will fail JSONSchema validation and you'll know it's time to update your fixtures and possibly the code which relies on those fixtures.
We have a web application (using Grails/Groovy) and we write unit tests and functional tests.
However, we are not writing integration tests.
With unit tests, we can catch some small issues and also, it helps us writing our codebase in modular, short and readable fashion.
Functional tests obviously helps us to know when a feature is broken.
What would be get from writing integration tests? What would be the benefits of the extra time spent writing these tests?
The question is "What would be get from writing integration tests? What would be the benefits of the extra time spent writing these tests?"
Your integration tests will ensure that your components work together with cross cutting concerns such as web services, db, session etc. You only need only few integration tests - As #bagheera's comment on TestPyramid. Be aware how you write integration tests because if you go overboard, it can really slow to run all of them, and harder to work with. When you compare them to Unit Tests, you don't get much benefit of writing them.
Addtional :
You need lot of Unit Tests - you already have this and it is a good sign. You don't want tests in between this, which is called "dirty hybrids" http://blog.stevensanderson.com/2009/08/24/writing-great-unit-tests-best-and-worst-practises/
From:
http://martinfowler.com/bliki/TestPyramid.html
The pyramid also argues for an intermediate layer of tests that act
through a service layer of an application, what I refer to as
SubcutaneousTests. These can provide many of the advantages of
end-to-end tests but avoid many of the complexities of dealing with UI
frameworks. In web applications this would correspond to testing
through an API layer while the top UI part of the pyramid would
correspond to tests using something like Selenium or Sahi..
In addition to checking your application's plumbing as #Raedwald mentioned, integration tests are great for testing that your persistence layer is working as you expect. Are cascades set up correctly? Is everything rolled back properly if something blows up during a transaction? It's often much easier to directly check this stuff with an integration test rather than a functional test.
I find they are useful for checking the 'plumbing' of an application. For checking that your units are connected together and that delegating objects meet the preconditions of the methods they delegating to.
I am new to testing in general and am working on a Grails application.
I want to write a test that says "when this action is called, the correct view is returned". I don't know how to go about deciding if I should make something like this a unit test or an integration test. Either test would show me what I want - how do I decide?
One problem with integration tests is their speed. For me, integration tests take 15+ seconds to start up. In that time, certain things do slip out of mind focus.
I prefer to go with unit tests that start in no more then 2 sec and can be run several times in those 15 seconds. Especially with mockDomain(). Especially with Grails 2.0 implementing criteria and named queries in unit tests.
One more argument for unit tests is they force you to decouple your code. Integration tests always tempt you to just rely on some other component existing and initialized.
From Grails Docs section 9.1
Unit testing are tests at the "unit" level. In other words you are
testing individual methods or blocks of code without considering for
surrounding infrastructure. In Grails you need to be particularity
aware of the difference between unit and integration tests because in
unit tests Grails does not inject any of the dynamic methods present
during integration tests and at runtime.
From Grails Docs section 9.2
Integration tests differ from unit tests in that you have full access
to the Grails environment within the test. Grails will use an
in-memory HSQLDB database for integration tests and clear out all the
data from the database in between each test.
What this means is that a unit test is completely isolated from the Grails environment whereas an integration test is not. According to Scott Davis, author of this article, it is acceptable to write only integration tests...
Unit vs. integration tests
As I mentioned earlier, Grails supports two basic types of tests: unit
and integration. There's no syntactical difference between the two —
both are written as a GroovyTestCase using the same assertions. The
difference is the semantics. A unit test is meant to test the class in
isolation, whereas the integration test allows you to test the class
in a full, running environment.
Quite frankly, if you want to write all of your Grails tests as
integration tests, that's just fine with me. All of the Grails
create-* commands generate corresponding integration tests, so most
folks simply use what is already there. As you'll see in just a
moment, most of the things you want to test require the full
environment to be up and running anyway, so integration tests are a
pretty good default. If you have noncore Grails classes that you'd
like to test, unit tests are perfectly fine.
First go through this chapter of the grails guide http://grails.org/doc/latest/guide/9.%20Testing.html
It talks about testing controllers and ability to get controller response like so :
controller.response.contentAsString
Now deciding on which test is more of an art rather than science. I prefer unit tests cause they are faster to run :)
Its a really interesting and challenging question to answer, but the truth is it really depends on what exactly you are testing.
Take the following test: "saving a book to the database". The hints are in the description. We are saying we need a book and we need a database, so in this case a unit test wont do because we need the integrated database.
My advice is write the full test description down and break it down like I did above. It will give you the hints to help you decide.
This is made easier with spock where you can use strings for test names.
I have been doing a lot a reading about unit testing.
Unit testing seems all well and good.
But it seems to miss a lot of the fundamentals of how the web works. User Interaction.
I have not seen any way a unit test could test for unexpected input, or test to make sure that an ajax call works etc.
Am I missing something here or is unit testing not really designed well for web development?
You are not missing anything.
Ideally unit testing is about testing a small piece of code, e.g. a class in isolation. For this you may want to use a unit testing tools such as JUnit or NUnit. Some people refer to this type of tests as developer tests.
In contrast to that you may want to test web applications as a whole. Some call this acceptance testing. For the latter you could use a tool such as Selenium. Tools like Selenium can test Ajax and other JavaScript as well.
You have even more options if you take a look at a tool like WebDriver as you will find that you can implement Selenium-based tests using a unit testing tool.
Take a look at Selenium.