HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Testing an abstract class

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
abstracttestingclass

Problem

I started writing a set of tests for my SageContextBase class, which needs to be abstract because the client code must derive from it (think of it as EF's DbContext - it can't be instantiated directly, but it packs a truckload of functionality) - I have 5 passing tests covering everything that should be happening inside the Open method:

```
[TestClass]
public class SageContextBaseOpenTests
{
private Mock GetMockView(string viewId)
{
var view = new Mock();
view.SetupAllProperties();
view.SetupGet(m => m.ViewId).Returns(viewId);
view.Setup(m => m.Compose(It.IsAny()));
view.Setup(m => m.Dispose());
view.Setup(m => m.Insert());
view.Setup(m => m.Delete());
view.Setup(m => m.Update());
view.Setup(m => m.FilterCount(It.IsAny()));

return view;
}

private Mock GetMockSession()
{
var dbLink = new Mock();
dbLink.SetupAllProperties();

const string headersViewId = "PO0620";
var headersView = GetMockView(headersViewId);
dbLink.Setup(m => m.OpenView(headersViewId)).Returns(headersView.Object);

const string detailsViewId = "PO0630";
var detailsView = GetMockView(detailsViewId);
dbLink.Setup(m => m.OpenView(detailsViewId)).Returns(detailsView.Object);

var session = new Mock();
session.SetupAllProperties();
session.Setup(m => m.OpenDbLink(It.IsAny(), It.IsAny())).Returns(dbLink.Object);

return session;
}

[TestMethod]
public void Open_InitializesSessionWithSpecifiedAppInfo()
{
// arrange
var credentials = new SageCredential("testuser", "testpwd", "testdb");
var appInfo = new SageAppInfo("testapp", "v42");

var session = GetMockSession();
var context = new TestSageContext(credentials, appInfo, session.Object);

// act
context.Open();

// assert
session.Verify(m => m.Init(It.IsAny(), appInfo)

Solution

Just a couple of things.

You repeat this set up in every test.

var credentials = new SageCredential("testuser", "testpwd", "testdb");
    var appInfo = new SageAppInfo("testapp", "v42");


Extract the fixtures into fields and create a [TestInitialize] routine. If you need to change them later, then you have a different fixture and should create a new test class anyway. It helps to keep your test classes small, focused, and clean.

The It.IsAny() method is useful for getting your test to initially pass, but I get hesitant when I see it sticking around in code that's "done". I get doubly hesitant when I see it in a Verify().

session.Verify(m => m.Init(It.IsAny(), appInfo));


It could be perfectly ok, but always worth a second look. It's a balancing act between making sure the tests go red if a breaking change is made, and not testing the implementation.

In a perfect world, we'd never have to Verify() anything. We would just Assert the output. We don't live in a perfect world, so this all might be fine, but it's definitely worth reflecting on.

Code Snippets

var credentials = new SageCredential("testuser", "testpwd", "testdb");
    var appInfo = new SageAppInfo("testapp", "v42");
session.Verify(m => m.Init(It.IsAny<string>(), appInfo));

Context

StackExchange Code Review Q#121492, answer score: 2

Revisions (0)

No revisions yet.