chevron-thin-right chevron-thin-left brand cancel-circle search youtube-icon google-plus-icon linkedin-icon facebook-icon twitter-icon toolbox download check linkedin phone twitter-old google-plus facebook profile-male chat calendar profile-male
Welcome to Typemock Community! Here you can ask and receive answers from other community members. If you liked or disliked an answer or thread: react with an up- or downvote.
0 votes
Hi all,

I'm new to TypeMock and I'm trying to get a really simple first test going.
Code under test:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using Microsoft.SharePoint;

namespace Simple
{
    public class SimpleWebPart : WebPart
    {
        public SimpleWebPart()
        {
            try
            {
                Web = SPContext.Current.Web;
            }
            catch
            {
                // allow external callers to set the web
            }
        }

        private SPWeb _web;
        public SPWeb Web 
        { 
            get; set; 
        }

        private Label label;

        protected override void CreateChildControls()
        {
            label = new Label();
            label.Text = "Hello World! blah2";
            Button button = new Button();
            button.Text = "My Button";
            button.Click += new EventHandler(button_Click);
            this.Controls.Add(label);
            this.Controls.Add(button);
            
            
        }

        public void button_Click(object sender, EventArgs e)
        {
            SPListItem item = Web.Lists["TestList"].Items.Add();
            item["Title"] = "testtitle";
            item.Update();
        }
    }
}


Test code:
using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TypeMock.ArrangeActAssert;
using Microsoft.SharePoint;
using Simple;

namespace SimpleWebPartTests
{
    /// <summary>
    /// Summary description for UnitTest1
    /// </summary>
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestMethod1()
        {
            var web = Isolate.Fake.Instance<SPWeb>(Members.ReturnRecursiveFakes);
            var item = Isolate.Fake.Instance<SPListItem>(Members.ReturnRecursiveFakes); // should be faked by Members.ReturnRecursiveFakes above?

            Isolate.WhenCalled(() => web.Lists["TestList"].Items.Add()).WillReturn(item); // do I need this?

            var list = web.Lists["TestList"];
            Assert.AreEqual(0, list.Items.Count);

            SimpleWebPart webpart = new SimpleWebPart();
            webpart.Web = web;

            webpart.button_Click(null,null);
            
            Assert.AreEqual(1, list.Items.Count);
        }
    }
}


The final Assert.AreEqual line fails though. What am I doing wrong? And is there more documentation I'm missing? The manual that comes with it only has one page on testing SharePoint - and that's really only a couple of examples.

Thanks for any help,

Phil.
asked by philbarr (680 points)

4 Answers

0 votes
Hi Phil

The reason that your Assert fails is that Web.Lists["TestList"].Items.Add();
returns fake SPListItem.
Since it's faked SPListItem it is not really updated the count is zero.

As I understand the test want to check that the SPListItem is updated at a specific index when a button is clicked.
You can do that by using Isolate.Verify methods.
Example:
[TestMethod]
public void TestMethod1()
{
    var fakeWeb = Isolate.Fake.Instance<SPWeb>(Members.ReturnRecursiveFakes);
    var fakeItem = Isolate.Fake.Instance<SPListItem>(Members.ReturnRecursiveFakes);
    Isolate.WhenCalled(() => fakeWeb.Lists["TestList"].Items.Add()).WillReturn(fakeItem);

    var list = fakeWeb.Lists["TestList"];
    Assert.AreEqual(0, list.Items.Count);

    SimpleWebPart webpart = new SimpleWebPart();
    webpart.Web = fakeWeb;
    webpart.button_Click(null, null);
    
    Isolate.Verify.WasCalledWithExactArguments(() => { fakeItem["Title"] = "testtitle"; });
    Isolate.Verify.WasCalledWithAnyArguments(() => fakeItem.Update());
}


The first verify will ensure that the item is updated at the index that you expect it to be updated and the second verify will ensure that the changes are saved.

:arrow: Notice the syntax of the line
Isolate.Verify.WasCalledWithExactArguments(() => { fakeItem["Title"] = "testtitle"; });
The part { fakeItem["Title"] = "testtitle"; } will tell the compiler that you are referring the "set indexer" and not to the "get indexer".

Please let me know if it helps.
answered by ohad (35.4k points)
0 votes
Thanks for your reply.

I don't understand how the modified test helps? It seems to be verifying that certain methods have been called? I don't want to test that, though, I want to test if my method has added an item to a list.

For example, if I am the writer of SimpleWebPart, and I am the writer of it's unit test, and suppose I don't know that you have to call item.Update() in order to commit changes, I'm going to write my method with:
SPListItem item = Web.Lists["TestList"].Items.Add();
item["Title"] = "testtitle"; 

and I'm going to write my test code with:
Isolate.Verify.WasCalledWithExactArguments(() => { fakeItem["Title"] = "testtitle"; }); 

so the unit test will pass, but my code won't actually update the list with the new item, because I'm only testing that method calls have taken place, not what their behavioural effect is.

I'm pretty new to Mocking in general, although I've been aware of Mocks and I've been using unit tests for quite a while, so it's very possible I'm missing the point here!

Any help greatly appreciated here.

Phil.
answered by philbarr (680 points)
0 votes
Hello Phil,

The problem with checking the SPList.Count is that because the test fakes the Add function and fake functions do not call their original code. In other words by faking SPList.Items.Add() we cause all calls to it to run a different code - in this test return a fakeItem.

Ohad suggested that instead of checking for count you can use Verify to make sure certain methods were called with specific arguments.

In case you do not want to check inner logic of the application (becuase it might change in the future) you can use DoInstead to count the times Items.Add was called and user the same assert:
int count = 0;
Isolate.WhenCalled(() => web.Lists["TestList"].Items.Add()).DoInstead((context) => 
    {
         count++;
         return item;
    });
    
   Assert.AreEqual(0, count); 

    //...

   Assert.AreEquals(1, count);
answered by dhelper (11.9k points)
0 votes
Thanks again,

What I was hoping for was some way of testing that I had used the SharePoint API correctly. The reason being that initially I didn't know I had to call item.Update().

It looks like there isn't a way of doing this, though. And that that's not really Isolator's intention. Instead, it's more of a way of testing that the logic of your method is correct. Hence, it becomes more useful in non-trivial examples?

That is, it's not possible to test the effect of your code, just that the business logic you've applied is correct?

I initially thought that the mock of SPList would maintain some kind of collection of mock SPListItems, and that they would be updated when I called SPListItem.Update().

Phil.
answered by philbarr (680 points)
...