./test.sh runs test.sh as a separate program. It may happen to be a bash script, if the file test.sh starts with #!/bin/bash. But it could be something else altogether.
. ./test.sh executeexecutes the code of the file test.sh inside the running instance of bash. It works as if the content file test.sh had been included textually instead of the . ./test.sh line. (Almost: there are a few details that differ, such as the value of $BASH_LINENO, and the behavior of the return builtin.)
source ./test.sh is identical to . ./test.sh in bash (in other shells, source may be slightly different or not exist altogether; . for inclusion is in the POSIX standard).
The most commonly visible difference between running a separate script with ./test.sh and including a script with the . builtin is that if the test.sh script sets some environment variables, with a separate process, only the environment of the child process is set, whereas with script inclusion, the environment of the sole shell process is set. If you add a line foo=bar in test.sh and echo $foo at the end of the calling script, you'll see the difference:
$ cat test.sh
#!/bin/sh
foo=bar
$ ./test.sh
$ echo $foo
$ . ./test.sh
$ echo $foo
bar