I have found that the key to writing good unit tests that interact with the database is making sure that the data is in a known state before and after the test. System.Transactions makes this very easy. All you have to do is wrap your unit test inside a TransactionScope and rollback at the end.
For example, in the test below, I am testing the update feature of my Customer data access class. To make sure I have a customer to update, I create it myself at the start of test, then I update it. At the end, scope.dispose() rolls back the whole thing. The database should look exactly like it was before my test.
[TestMethod]
public void CanUpdateCustomer()
{
using (TransactionScope scope = new TransactionScope) {
Customer customer = CreateTestCustomer();
customerDac.saveCustomer(customer);
customer.Phone1 = "804-555-1212";
customerDac.updateCustomer(customer);
// TODO: verify that update works
scope.Dispose(); // roll back
}
} Here are a few more tips I have for unit tests that interact with the database:
For Java programmers, try using Spring TestContext Framework. It’s a bit more complicated to use but it works just as well.
To list available contexts: kubectl config get-contexts To show the current context: kubectl config current-context…
kubectl exec -it <podname> -- sh To get a list of running pods in the…
# Create a soft symbolic link from /mnt/original (file or folder) to ~/link ln -s…
git config --global user.name "<your name>" git config --global user.email "<youremail@somewhere.com>" Related Commands Show current…
TypeScript/JavaScript function getLastMonday(d: Date) { let d1 = new Date(d.getFullYear(), d.getMonth() + 1, 0); let…
I had to do some SMTP relay troubleshooting and it wasn't obvious how to view…
View Comments
This appraoch makes your tests a little clunky, and you are adding more logic to your tests than required. Checking that CRUDs work is a part of the Database Unit tests.
Strictly speaking your appraoch above is not for Unit Tests, but can be more closely attributed to Integration Tests.
Love this idea. So simple, yet very effective.
I have to slightly disagree with Gary. How would you then run an automated unit test without having to manually update your test data each time? For example, say your unit test inserts "Johh Doe" with a Client_Insert proc. Let's say your unit test then runs a read to make sure the insert was successful, and you have to test if "John Doe" now exists. No matter what specifically you test, you would have to update the test manually before you can run it again.
Additionally, you can still test your CRUD operations AND use transactions. Why not run whatever you are testing (say, an insert), and then run a read operation to verify, inside the same transaction scope? That way, you can fully test your CRUD operations, while still having the flexibility to roll it back when the test is complete.
I personally like to separate my Database Unit Tests from Data Access Unit Tests.. meaning that I won't test my CRUD operations in the same unit test that is testing something like a DAO.
Great article Chinh Do!