I want to be able to mock the object that is returned by SPServer.Local but I can't seem to do it in typemock. At the moment when I debug, I see that SPServer.Local returns a null object of type SPServer. Shouldn't typemock be swapping out this instance with my fake instance? Is there something I'm doing wrong? The code runs fine on the sharepoint server.
[TestInitialize]
public void Setup()
{
fakeSite = Isolate.Fake.Instance<SPSite>(Members.ReturnRecursiveFakes);
Isolate.Swap.NextInstance<SPSite>().With(fakeSite);
fakeServer = Isolate.Fake.Instance<SPServer>(Members.ReturnRecursiveFakes);
Isolate.Swap.NextInstance<SPServer>().With(fakeServer);
sharePointStorageRepository = new SharePointStorageRepository();
}
[TestMethod]
[Isolated]
public void CreateHRFolderMethodCreatesHRFolder()
{
// arrange
// some arrange logic here
// act
var actual = sharePointStorageRepository.Create();
// assert
Assert.AreEqual(expected, actual);
}
This is the bit of code that is being run:
internal static Guid GetSiteGuid(string serverRelativeUrl, string webApplicationName)
{
Guid? guid = null;
SPServer myServer = SPServer.Local;
foreach (var serviceInstance in myServer.ServiceInstances.Where(si => si.Service is SPWebService)){
var service = (SPWebService) serviceInstance.Service;
var webapp = service.WebApplications.SingleOrDefault(wa => wa.DisplayName == webApplicationName);
if (webapp != null){
var site = webapp.Sites.SingleOrDefault(wa => wa.ServerRelativeUrl == serverRelativeUrl);
if (site != null) guid = site.ID;
}
}
if (!guid.HasValue){
throw new FileNotFoundException(
String.Format(
"Cannot find Site Collection with WebApplication \"{1}\" and ServerRelativeUrl \"{2}\" running on \"{0}\"",
myServer.Address, webApplicationName, serverRelativeUrl));
}
return guid.Value;
}
Thanks all!
I don't work in SharePoint, but something I noticed: You're not actually mocking the return of SPServer.Local anywhere. I think that's the missing step. I'm also not entirely sure you need to SwapNextInstance since I don't see anywhere that is actually creating an SPServer object.
That would change your test code to:
[TestInitialize]
public void Setup()
{
// I don't see where you're using SPSite, so I assume it's in code
// not being shown; otherwise you can remove this.
fakeSite = Isolate.Fake.Instance<SPSite>(Members.ReturnRecursiveFakes);
Isolate.Swap.NextInstance<SPSite>().With(fakeSite);
fakeServer = Isolate.Fake.Instance<SPServer>(Members.ReturnRecursiveFakes);
// INSTEAD OF THIS: Isolate.Swap.NextInstance<SPServer>().With(fakeServer);
// DO THIS:
Isolate.WhenCalled(() => SPServer.Local).WillReturn(fakeServer);
sharePointStorageRepository = new SharePointStorageRepository();
}
That WhenCalled method will mean that any time anyone asks for SPServer.Local, it'll return your fake instance.
Note that I see in the code being tested that you get the ServerInstances property. I don't see any specific return values getting set up, so I assume you're controlling the rest of the stuff in the omitted "arrange" logic.
Related
I am very new using Moq and unit tests.
I have been watching videos and reading different articles but I can't find the right example.
I am trying to mock a method that returns list of a object, but I'm getting this error
Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException: 'Assert.AreEqual failed.
Expected:<System.Collections.Generic.List'1[BusinessLayer.Model.XSIPhoneTrunkDetails]>. Actual:<System.Collections.Generic.List'1[BusinessLayer.Model.XSIPhoneTrunkDetails]>.
This is my code:
Controller:
public List<XSIPhoneTrunkDetails> GetTrunksRange(LocationVM location)
{
//var response = false;
List<XSIPhoneTrunkDetails> newDetails = new List<XSIPhoneTrunkDetails>();
if (!string.IsNullOrWhiteSpace(location.TrunksRange) && !location.TrunksRange.Equals("[]"))
{
var xSIPhoneTrunkDetails = JsonConvert.DeserializeObject<List<XSIPhoneTrunkDetails>>(location.TrunksRange);
foreach (var item in xSIPhoneTrunkDetails)
{
if (item.RangeStart.Equals(item.RangeEnd))
item.RangeEnd = String.Empty;
if (item.XSIPhoneTrunkDetailsID <= 0)
newDetails.Add(item);
}
}
return newDetails;
}
Interface:
public interface ILocation
{
List<XSIPhoneTrunkDetails> GetTrunksRange(LocationVM location);
}
My unit test
[Fact]
public void ShouldGetTrunkRange()
{
using (var mock = AutoMock.GetLoose())
{
var phone = GetLocationVMsNotRange().First();
var item = new List<BusinessLayer.Model.XSIPhoneTrunkDetails>();
mock.Mock<ILocation>()
.Setup(x => x.GetTrunksRange(phone))
.Returns(item);
var cls = mock.Create<Location>();
var result = cls.GetTrunksRange(phone);
Microsoft.VisualStudio.TestTools.UnitTesting.Assert.AreEqual(item.ToList(), result.ToList());
}
}
What am I doing wrong?
Use loop to iterate through the list and assert individual objects like this,
Assert.True(item.Equals(result));
If you use loop:
Assert.True(item[0].Equals(result[0]));
the code is not exact just to give you an idea.
Also another thing you can assert the list count or property values of the objects using loop. Do what works, good luck!
I haven't find the way to make activitySource.StartActivity return non-null activity, which is different comparing to DiagnosticSource.StartActivity behavior. Is it expected? Am I'missing something obvious?
I can see docs says: "The created activity object, if it had active listeners, or null if it has no event listeners." The following test still fails, what's the correct way of initializing ActivityListener? The package I'm using is "System.Diagnostics.DiagnosticSource" Version="5.0.0".
[TestMethod]
public void Start_Not_Null_When_ActivityListener_Added_And_ShouldListenTo_Explicitly_Defined_Activity()
{
var activitySource = new ActivitySource("ActivitySourceName");
var activityListener = new ActivityListener
{
ShouldListenTo = s => true
};
ActivitySource.AddActivityListener(activityListener);
using var activity = activitySource.StartActivity($"MethodType:/Path");
Assert.IsNotNull(activity);
}
This test pass with the help from github:
[TestMethod]
public void Start_Not_Null_When_ActivityListener_Added_And_ShouldListenTo_Explicitly_Defined_Activity()
{
var activitySource = new ActivitySource("ActivitySourceName");
var activityListener = new ActivityListener
{
ShouldListenTo = s => true,
SampleUsingParentId = (ref ActivityCreationOptions<string> activityOptions) => ActivitySamplingResult.AllData,
Sample = (ref ActivityCreationOptions<ActivityContext> activityOptions) => ActivitySamplingResult.AllData
};
ActivitySource.AddActivityListener(activityListener);
using var activity = activitySource.StartActivity("MethodType:/Path");
Assert.IsNotNull(activity);
}
The answer to this is you need to include a ActivitySamplingResult that's not set to None. The default appears to be none. MaGu's answer works because they set:
Sample = (ref ActivityCreationOptions activityOptions) => ActivitySamplingResult.AllData
The documentation for the method around StartActivity says it needs a listener but this is not the complete story you need an active listener that will do something with the activity. Setting the sample to None means it's effectively not in
I'm having trouble figuring out why I can't test my driver variable, it keeps coming back null with I call Start(). I basically would like to access that variable and test it.
My current test that isn't working:
[TestMethod]
public void Start_Default_IsChrome2()
{
var dummyManager = new Mock<IRemoteDriver>();
var mockDriver = new Mock<IWebDriver>();
dummyManager.Setup(x => x.CreateRemoteWebDriver(new ChromeOptions()))
.Returns(It.IsAny<RemoteWebDriver>());
var session = new SauceSession(dummyManager.Object);
//The Start() keeps returning a null object
var driver = session.Start();
var capabilities = driver.Capabilities;
capabilities.GetCapability("browserName").Should().Be("chrome");
}
Dependency to be mocked
public interface IRemoteDriver
{
IWebDriver CreateRemoteWebDriver(ChromeOptions chromeOptions);
}
Subject Under Test
public SauceSession(IRemoteDriver driverManager)
{
remoteDriverManager = driverManager;
}
public RemoteWebDriver Start()
{
sauceUserName = Environment.GetEnvironmentVariable("SAUCE_USERNAME", EnvironmentVariableTarget.User);
sauceAccessKey = Environment.GetEnvironmentVariable("SAUCE_ACCESS_KEY", EnvironmentVariableTarget.User);
sauceOptions = new Dictionary<string, object>
{
["username"] = sauceUserName,
["accessKey"] = sauceAccessKey
};
var chromeOptions = new ChromeOptions
{
BrowserVersion = "latest",
PlatformName = "Windows 10",
UseSpecCompliantProtocol = true
};
chromeOptions.AddAdditionalCapability("sauce:options", sauceOptions, true);
//This keeps returning a null
return (RemoteWebDriver)remoteDriverManager.CreateRemoteWebDriver(chromeOptions);
}
If it helps, the Concrete implementation works just fine and that test looks like this:
[TestMethod]
public void Start_Default_IsChrome()
{
var session = new SauceSession();
var driver = session.Start();
var capabilities = ((RemoteWebDriver)driver).Capabilities;
capabilities.GetCapability("browserName").Should().Be("chrome");
}
Everything else is the same except the object that I set here:
public SauceSession()
{
remoteDriverManager = new ConcreteRemoteWebDriver();
}
class ConcreteRemoteWebDriver : IRemoteDriver
{
public IWebDriver CreateRemoteWebDriver(ChromeOptions chromeOptions)
{
return new RemoteWebDriver(new Uri("https://ondemand.saucelabs.com/wd/hub"),
chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600));
}
}
Here's the RemoteWebDriver:
public class RemoteWebDriver : IWebDriver, ISearchContext, IDisposable, IJavaScriptExecutor, IFindsById, IFindsByClassName, IFindsByLinkText, IFindsByName, IFindsByTagName, IFindsByXPath, IFindsByPartialLinkText, IFindsByCssSelector, ITakesScreenshot, IHasInputDevices, IHasCapabilities, IHasWebStorage, IHasLocationContext, IHasApplicationCache, IAllowsFileDetection, IHasSessionId, IActionExecutor
You've done your setup improperly.
dummyManager.Setup(x => x.CreateRemoteWebDriver(new ChromeOptions()))
.Returns(It.IsAny<RemoteWebDriver>());
Two things here:
You're matching on precisely an instance of new ChromeOptions(). When determining which object to return, Moq will check if the arguments passed to CreateRemoteWebDriver are the same as the ones provided in the setup. It's unlikely that
new ChromeOptions
{
BrowserVersion = "latest",
PlatformName = "Windows 10",
UseSpecCompliantProtocol = true
};
and
new ChromeOptions()
will evaluate as equal, meaning that this setup won't be matched.
You probably just meant to use It.IsAny<ChromeOptions>(), like this
dummyManager.Setup(x => x.CreateRemoteWebDriver(It.IsAny<ChromeOptions>()))
The second issue is that your return value is explicitly null.
It.IsAny<T>() always returns the default value for T. The It methods are all only used for argument matching within the Setup expression. If you use them outside of a setup expression, you're just going to get the default value of the generic argument, which in this case is a null value. It's a shame that the Moq library doesn't make this improper usage a loud error message. Consequently, you'll need to provide an actual instance of RemoteWebDriver as a return value. (Or if you can decouple the implementation from a particular concrete type, you could just return something that implements IWebDriver.)
That value could be another Mock object, potentially, but it needs to be something you've either created ahead of time, or something that can be created via the Returns callback.
A correct setup might look something like:
var mockDriver = new Mock<RemoteWebDriver>();
dummyManager.Setup(x => x.CreateRemoteWebDriver(It.IsAny<ChromeOptions>()))
.Returns(mockDriver.Object); //This could throw an exception if RemoteWebDriver needs arguments.
A small caveat is that you will actually create a RemoteWebDriver instance as a result. If that has undesirable side effects (such as creating a chrome window), you will want to consider changing your strategy from using a particular concrete type to some interface or abstract class. If you did that, the setup might look something like the below:
var mockDriver = new Mock<IWebDriver>();
dummyManager.Setup(x => x.CreateRemoteWebDriver(It.IsAny<ChromeOptions>()))
.Returns(mockDriver.Object);
I created a function that verifies some rules. The function is supposed to return a bool whenever an element of a list matches an element of another list.
Here is the relevant code of the Rule Class
public override TestResult Execute()
{
Instrument ins = (Items.Length > 0) ? Items[0] as Instrument : null;
string errorInfo;
if (ins == null)
{
Result.Message = "Unable to perform test";
Result.Status = ResultStatus.Error;
return Result;
}
if (MPICSupportDB(ins))
{
Result.Message = "DB not supported by MPIC";
Result.Status = ResultStatus.Yellow;
}
else
{
Result.Status = ResultStatus.Green;
}
return Result;
}
private bool MPICSupportDB(Instrument ins)
{
IServiceProviderFactory serviceFactory = new WebServiceProviderFactory();
IInterfaceAssignmentService wService = serviceFactory.CreateInterfaceAssignmentService();
InterfaceAssignment wAssignments = wService.LoadAssignmentGroup("R4");
return ins.Connections.OfType<InterfaceConnection>()
.Where(conn => conn.Card.IsDB)
.Any(conn => wAssignments.PartMasters
.Any(partNumber => (conn.CardPartNumber == partNumber.PartNumber)));
}
I am trying to test the function MPICSupportDB in a unit test. So far I have started creating my unit test (below), but now I'm lost and I have no idea what to do.
[TestMethod]
public void TestForcompatibleDB()
{
var ins = new Instrument();
var serviceFactoryMock = new Mock<IServiceProviderFactory>();
var wserviceTest = new Mock<IInterfaceAssignmentService>();
var wassagnementTest = new Mock<InterfaceAssignment>();
// adding an MPIC card
ins.Connections.Add(AddCard(CardType.MPIC, "MA505400612268", "CARD1", 0, ins));
// adding an MPIC daughterboard
ins.Connections.Add(AddCard(CardType.GPIM_DB, "MA335022012268", "DB1", 1, ins));
var rule = new Rule026(RuleApplicability.Test, new object[] { ins });
var result = rule.Execute();
Assert.IsNotNull(result);
Assert.AreEqual(ResultStatus.Green, result.Status);
}
The problem is that classes like Webservice and factoryService cannot be run directly in a unit test.
Can someone explain to me how to properly mock these object and make my test run?
You need to provide the IServiceProviderFactory to your Rule026 class, rather than constructing it within the class. This will allow you to use your Mocks that you're creating. The most common approach would be through constructor injection. You haven't provided the Constructor for your Rule class, but if you modify it to something like this:
public Rule026(/*otherArgs*/, IServiceProviderFactory scpFactory = null) {
if(null == scpFactory)
scpFactory = new ServiceProviderFactory();
}
_serviceProviderFactory = scpFactory;
}
Then you will be able to inject the factory from your tests, whilst not having to update all of the code currently constructing Rules. Moving to an IOC container to provide the dependencies, or removing the default and forcing the clients to create the factory in order to able to instantiate the Rule may be preferable, depending on your situation.
Once you can pass in your mocks, you just need to setup a return chain to allow the mocks to return each other. Something like:
var serviceFactoryMock = new Mock<IServiceProviderFactory>();
var wserviceTest = new Mock<IInterfaceAssignmentService>();
var wassagnementTest = new Mock<InterfaceAssignment>();
serviceFactoryMock.Setup(x=>x.CreateInterfaceAssignmentService())
.Returns(wserviceTest.Object);
wserviceTest.Setup(x=>x.CreateInterfaceAssignmentService())
.Returns(wassagnementTest.Object);
wassagnementTest.Setup(x=>x.LoadAssignmentGroup(It.IsAny<string>()))
.Returns(cannedInterfaceAssignmentResponse);
And then supply the mock when constructing your object:
var rule = new Rule026(RuleApplicability.Test,
new object[] { ins },
serviceFactoryMock.Object);
You may also want to add verification etc to your mocks, depending on what you're trying to test and your particular style of testing.
I have an application that takes a dictionary of files (file type, and list of file names) and copies the files from the original directory into another location.
I've already got the basic code for the copy process, but I need to do some unit tests so it is as robust as possible.
I have wrapper class that I am using so I can test that the System.IO methods are called as I expect, but I am having some difficulty figuring out how to form the tests as there are foreach and switch statements in the code.
Sample code below:
private IFileSystemIO _f;
public CopyFilesToDestination(IFileSystemIO f){
_f = f;
}
public void Cpy_Files(Dictionary<string, List<string>> files)
{
// get a list of the file types in the directory
var listOfFileTypes = new List<string>(files.Keys);
foreach (var fileType in listOfFileTypes){
var fileList = files[fileType].ToList();
foreach (var file in fileList){
switch(fileType){
case ".txt":
_f.Copy(file, #"c:\destination\text");
break;
case ".dat":
_.Copy(file, #"c:\destination\data");
break;
}
}
}
}
To test the above I had thought I would use a mock dictionary object, set up with a list of file types and paths:
public virtual Dictionary<string, List<string>> FakeFiles(){
return fakeDictionary = new Dictionary<string, List<string>>(){
{".txt", new List<string>(){
"c:\test\file1.txt",
"c:\test\file2.txt"
}
},
{".dat", new List<string>(){
"c:\test\file1.dat",
"c:\test\file2.dat"
}
};
}
}
The first test I came up with looks like this:
[Test]
public void Should_Copy_Text_Files(){
var dictionary = new FakeDictionary().FakeFiles();
var mockObject = MockRepository.GenerateMock<IFileSystemIO>();
var systemUnderTest = new CopyFileToDestination(mockObject);
systemUnderTest.Cpy_Files(dictionary);
// I think this means "test the operation, don't check the values in the arguments" but I also think I'm wrong
mockObject.AssertWasCalled(f => f.Copy("something", "something"), o => o.IgnoreArguments());
}
My first problem is: How do I test for a specific file type, such as ".txt"?
Then how do I test the loops? I know with the mocked dictionary that I only have two items, do I leverage this to form the test? How?
I think I may be close to a solution, but I am running out of time/patience hunting it down. Any help is greatly appreciated.
Thanks
Jim
I tried using Roberts solution, but as I stated, I have too many different file types to set up each test case individually. The next thing I tried was setting up a TestCaseSource, but every time I ran the test for that it marked the test as ignored:
[Test, TestCaseSource(typeof(FakeDictionary), "TestFiles")]
public void Cpy_Files_ShouldCopyAllFilesInDictionary(string extension, string fielName) {
// Arrange
var mockObject = MockRepository.GenerateMock<IFileSystemIO>();
var systemUnderTest = new CopyFileToDestination(mockObject);
// Act
systemUnderTest.Cpy_Files(dictionary);
// Assert
mockObject.AssertWasCalled(f => f.Copy(extension, fileName));
}
The data source is below:
public static Dictionary<string, string> TestFiles{
get
{
return new Dictionary<string, string>()
{
{".txt",
"C:\\test\\test1.txt"},
{".txt",
"c:\\test\\test2.txt"}
};
}
}
What I finally worked out uses the times to repeat option in Rhino and is really pretty simple:
[Test]
public void Cpy_Files_ShouldCopyAllFilesInDictionary(){
// Arrange
var mockObject = MockRepository.GenerateMock<IFileSystemIO>();
var systemUnderTest = new CopyFileToDestination(mockObject);
// Act
systemUnderTest.Cpy_Files(dictionary);
// Assert
// I know how many objects are in my fake dictionary so I set the times to repeat as a const
const int timesToRepeat = 2;
// now I just set the values below. I am not testing file names so the test will ignore arguments
mockObject.AssertWasCalled(f => f.Copy("",""), options => options.Repeat.Times(timesToRepeat).IgnoreArguments());
}
I hope this helps someone else with a similar problem.
I would try making use of the TestCase attribute:
[TestCase(".txt", "c:\test\file1.txt")]
[TestCase(".txt", "c:\test\file2.txt")]
[TestCase(".dat", "c:\test\file1.dat")]
[TestCase(".dat", "c:\test\file2.dat")]
public void Should_Copy_Text_Files(string extension, string fileName){
var dictionary = new FakeDictionary().FakeFiles();
var mockObject = MockRepository.GenerateMock<IFileSystemIO>();
var systemUnderTest = new CopyFileToDestination(mockObject);
systemUnderTest.Cpy_Files(dictionary);
mockObject.AssertWasCalled(f => f.Copy(extension, fileName));
}
This will run the test separately for each TestCase attribute, passing the parameters it contains into the test method. That way you can test that each item in your dictionary was "copied" without using multiple asserts in the same test.