Are these unit tests accurate?

I'm trying to understand test-based development, and I wonder if these unit tests are good. I have an interface that looks like this:

public interface IEntryRepository { IEnumerable<Entry> FetchAll(); Entry Fetch(int id); void Add(Entry entry); void Delete(Entry entry); } 

And then this class that implements this interface:

 public class EntryRepository : IEntryRepository { public List<Entry> Entries {get; set; } public EntryRepository() { Entries = new List<Entry>(); } public IEnumerable<Entry> FetchAll() { throw new NotImplementedException(); } public Entry Fetch(int id) { return Entries.SingleOrDefault(e => e.ID == id); } public void Add(Entry entry) { Entries.Add(entry); } public void Delete(Entry entry) { Entries.Remove(entry); } } 

Those are the unit tests that I have written so far, are they beautiful or should I do something else? Should I mock EntryRepository?

 [TestClass] public class EntryRepositoryTests { private EntryRepository rep; public EntryRepositoryTests() { rep = new EntryRepository(); } [TestMethod] public void TestAddEntry() { Entry e = new Entry { ID = 1, Date = DateTime.Now, Task = "Testing" }; rep.Add(e); Assert.AreEqual(1, rep.Entries.Count, "Add entry failed"); } [TestMethod] public void TestRemoveEntry() { Entry e = new Entry { ID = 1, Date = DateTime.Now, Task = "Testing" }; rep.Add(e); rep.Delete(e); Assert.AreEqual(null, rep.Entries.SingleOrDefault(i => i.ID == 1), "Delete entry failed"); } [TestMethod] public void TestFetchEntry() { Entry e = new Entry { ID = 2, Date = DateTime.Now, Task = "Testing" }; rep.Add(e); Assert.AreEqual(2, rep.Fetch(2).ID, "Fetch entry failed"); } } 

Thanks!

+4
source share
8 answers

Just from the head ...

Although your add testing really only checks the framework:

  • You have 1 item, this one is good.
  • how about adding product items (I mean ridiculous amounts - for what value of n entries is the container added?)
  • How about adding items? (zero entry)
  • If you add items to the list, are they in a specific order? should they be?

similar to your sample:

  • what happens in your sample (x) if x> rep.Count?
  • what happens if x <0?
  • what happens if rep is empty?
  • meets the performance requirements (what is its algorithmic complexity? is it within the range when there is only one record and when there are a ridiculously large number of records?

The book has a good checklist Pragmatic testing of modules (good book, recommended)

  • Are the results correct?
  • All boundary conditions are CORRECT
    • Meets the expected format
    • Ordered correctly
    • In a reasonable range
    • It refers to any external dependencies.
    • Is this cardinality right? (correct number of values)
    • does it complete the correct amount of time (real or relative)
  • You can check the inverse relationship
  • You can cross-check the results using another proven method.
  • Can you force the error conditions.
  • Are performance characteristics within boundaries
+7
source

Here are some thoughts:

Positive

  • Module Testing!
  • You comply with the agreement Arrange, Act, Assert

Negative

  • Where is the test to delete a record when there is no record?
  • Where is the test to retrieve a record when there is no record?
  • What should happen if you add two entries and delete them? Which one should I leave?
  • Entries must be publicly available. The fact that one of your statements calls rep.Entries.SingleOrDefault tells me that you are not building the class correctly.
  • Your test naming is a bit vague; Usually a good example is: {MethodName}_{Context}_{Expected Behavior} , which eliminate the "test" redundancy.

As a newbie to TDD, I found Test-Driven Development By Example to get a lot of help. Secondly, Roy Osherove has a good Test Review video tutorials, check them out.

+4
source

Before answering, let me state that I am quite new to unit testing and by no means an expert, so take everything I declare with salt.

But I feel that your unit tests are pretty much redundant. Many of your methods are simple, since your AddEntry method is just a call to the add list method. You are not testing your code, testing the Java library.

I would recommend only unit testing methods containing the logic you write. Avoid testing obvious methods like getters and setters because they work at the most basic level. This is my philosophy, but I know that some people really believe in testing obvious methods, it just seems to me that this is pointless.

+1
source

It seems so. I personally would like to give my tests some more descriptive names, but this is a more personal preference.

You can use a mockery of the dependencies of the tested class, EntryRepository is the class under the test, so you do not need to scoff at it, otherwise you will end up testing the mock implementation instead of the class.

Just to give a quick example. If your EntryRepository will use a backend database to store records instead of a list, you can enter a layout implementation for the material to access the data instead of calling a real database.

0
source

It looks like a great start, but you should try as much as possible to check the "borderline" cases. Think about what might cause your methods to fail. Will empty input be added for adding or removing? Try writing tests that run every possible code path. Writing tests in this way will make your test suite more useful in the future if you make any changes to the code.

In addition, for each test method, it is useful that the test object is in the same state as when it was called. I noticed that your TestFetchEntry method adds an element to the EntryRepository, but never removes it. The presence of each method does not affect the state of the test object, which facilitates the execution of a series of tests.

0
source

You should not taunt IEntryRepository, since the implementation class is a test class. You may want to mock the List<Entry> and enter it, and then just verify that the methods that you call through your public interface are called appropriately. This would be just an alternative to how you implemented it, and not necessarily better - if you do not want the class to support it according to the class you entered, in this case writing tests in this way will force this behavior.

You may need a few more tests to make sure that when you insert a record, the right record is inserted. Similarly with deletion - insert a couple of records, then delete them and make sure that the corresponding one has been deleted. After you come up with tests to get the code to do what you want, keep thinking about how you can mess up the code and write tests to make sure that doesn't happen. Of course, this class is pretty simple, and you can make sure that the tests you have are enough. However, this does not require much difficulty to make it a check for extreme cases and unexpected behavior.

0
source

For a beginner TDD and for this particular class, your tests are fine. +1 to complete the effort.

Submit another question as you move on to more complex scenarios, including dependency injection and ridicule. Everything becomes really interesting here;).

0
source

Looks nice. You must use transactions (or create a new instance of the repository in TestInitialize) to ensure that the tests are completely isolated.

Also use more descriptive testing methods such as When_a_new_entity_is_added_to_a_EntryRepository_the_total_count_of_objects_should_get_incremented

-1
source

All Articles