I have this class POCO
public class BankTransaction
{
public int Id { get; set; }
public decimal TransactionAmount { get; set; }
public TransactionTypeEnum TransactionType { get; set; }
public int BankAccountId { get; set; }
public BankTransaction(decimal TransactionAmount)
{
this.TransactionAmount = TransactionAmount;
}
}
public enum TransactionTypeEnum
{
Deposit, Withdraw, ThirdPartyTransfer
}
and this repository class insert the transaction
public class BankTransactionRepository : IBankTransactionRepository
{
// Mock DB
public List<BankTransaction> bankTransactions { get; private set; }
public BankTransactionRepository()
{
bankTransactions = new List<BankTransaction>();
}
public void InsertTransaction(BankTransaction bankTransaction)
{
bankTransactions.Add(bankTransaction);
}
}
and here is my xUnit unit test for InsertTransaction method which works except for expected.Should().Contain(trans); which support to check if trans object exists in expected list.
public class BankTransactionsTest
{
private BankTransactionRepository _bankTransaction;
public BankTransactionsTest()
{
_bankTransaction = new BankTransactionRepository();
}
// Arrange
[Theory, MemberData(nameof(InsertTransaction_InsertShouldPass_Data))]
public void InsertTransaction_InsertShouldPass(BankTransaction trans, List<BankTransaction> expected)
{
// Act
_bankTransaction.InsertTransaction(trans);
// Assert
Assert.Equal(expected.Count, _bankTransaction.bankTransactions.Count);
// Fluent Assertions to check if trans is in 'expected' list.
expected.Should().Contain(trans);
}
public static TheoryData<BankTransaction, List<BankTransaction>> InsertTransaction_InsertShouldPass_Data()
{
return new TheoryData<BankTransaction, List<BankTransaction>>
{
{
new BankTransaction(200.00M),
new List<BankTransaction>(){new BankTransaction(200.00M)}
},
{
new BankTransaction(50.50M),
new List<BankTransaction>(){new BankTransaction(50.50M)}
},
};
}
}
Change the approach to be more explicit about asserting the expected behavior:
That the object inserted when InsertTransaction is invoked, is actually contained in the subject under test.
public class BankTransactionsTest
{
private BankTransactionRepository _bankTransaction;
public BankTransactionsTest()
{
_bankTransaction = new BankTransactionRepository();
}
// Arrange
[Theory, MemberData(nameof(InsertTransaction_InsertShouldPass_Data))]
public void InsertTransaction_InsertShouldPass(BankTransaction transaction)
{
// Act
_bankTransaction.InsertTransaction(transaction);
// Assert
_bankTransaction.bankTransactions.Should().ContainEquivalentOf(transaction);
}
public static TheoryData<BankTransaction> InsertTransaction_InsertShouldPass_Data()
{
return new TheoryData<BankTransaction>
{
new BankTransaction(200.00M),
new BankTransaction(50.50M)
};
}
}
Related
I have this code:
Class VM
{
var MyVm;
public VM(ExternalEntities externalEntities){
MyVm = externalEntities.Reflcation.VM;
}
public bool IsVmPowerOn(){
//Do something
}
}
[TestMethod]
public void TestVM()
{
private Mock<IExternalEntities> m_externalEntities = new Mock<IExternalEntities>();
private Mock<IReflection> m_reflection = new Mock<IReflection>();
private Mock<IVm> m_vm= new Mock<IVm>();
m_externalEntities.Setup(x => x.Reflaction).Return(m_reflection.object);
m_reflection.Setup(x => x.VM).Return(m_vm.Object);
var testee = new VM(externalEntity.Object)
var ans = testee.IsVmPowerOn();
Assert.IsTrue(ans);
}
The problem is that externalEntities.Reflcation is null and the test throws a NullReferenceException so it can't activate the Vm property.
The test can't pass constructor.
The following code also throws a NullReferenceException:
m_externalEntities.Setup(x => x.Reflaction.VM).Return(m_vm.object);
How do you test this kind of code?
Why do I receive null after the setup and not the mock object?
You had a lot of compilation errors and missing pieces in your code. It was not compiling as-is. That being said, I fixed it up for you. Not sure what your trying to accomplish but this works.
public interface IVm
{
IVm MyVm { get; set; }
}
public class VM : IVm
{
public IVm MyVm { get; set; }
public VM(IExternalEntities externalEntities)
{
MyVm = externalEntities.Reflaction.VM;
}
public bool IsVmPowerOn()
{
//Do something
return true;
}
}
public interface IExternalEntities
{
IReflection Reflaction { get; set; }
}
public class ExternalEntities : IExternalEntities
{
public IReflection Reflaction { get; set; }
public ExternalEntities()
{
Reflaction = new Reflection();
}
}
public interface IReflection
{
IVm VM { get; set; }
}
public class Reflection : IReflection
{
public IVm VM { get; set; }
public Reflection()
{
VM = new VM(null);
}
}
Then using that, your test would look like this.
[TestMethod]
public void TestVM()
{
Mock<IExternalEntities> m_externalEntities = new Mock<IExternalEntities>();
Mock<IReflection> m_reflection = new Mock<IReflection>();
Mock<IVm> m_vm = new Mock<IVm>();
m_externalEntities.Setup(x => x.Reflaction).Returns(m_reflection.Object);
m_reflection.Setup(x => x.VM).Returns(m_vm.Object);
var testee = new VM(m_externalEntities.Object);
var ans = testee.IsVmPowerOn();
Assert.IsTrue(ans);
}
I am receiving an exception: "object reference not set to an instance of an object".
I am trying to evaluate if Location and Manufacturing classes method ResetAllProperties() are executed.
What em I doing wrong?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Rhino.Mocks;
namespace Test
{
public class Engine
{
public Engine() { }
public EngineStatus Status { get; internal set; }
public virtual EngineLocation Location { get; set; }
public virtual EngineManufacturing Manufacturing { get; set; }
}
public abstract class EngineStatus
{
protected readonly Engine engine = null;
public EngineStatus(Engine engine)
{
this.engine = engine;
}
public abstract void ResetAllProperties();
}
public class FirstEngineStatus : EngineStatus
{
public FirstEngineStatus(Engine engine) : base(engine) { }
public override void ResetAllProperties()
{
this.engine.Location.ResetAllProperties();
this.engine.Manufacturing.ResetAllProperties();
}
}
public class EngineLocation
{
public string CustomerName { get; set; }
public virtual EngineManufacturing Manufacturing { get; set; }
public virtual Engine Engine { get; set; }
public void ResetAllProperties()
{
this.CustomerName = null;
}
}
public class EngineManufacturing
{
public Nullable<DateTime> EntryDate { get; set; }
public virtual EngineLocation Location { get; set; }
public virtual Engine Engine { get; set; }
public void ResetAllProperties()
{
this.EntryDate = null;
}
}
[TestClass]
public class Test
{
[TestMethod]
public void ResetAllProperties_AssertWasCalled()
{
// Arrange
var engine = MockRepository.GenerateMock<Engine>();
var status = MockRepository.GeneratePartialMock<FirstEngineStatus>(engine);
engine.Stub(action => action.Location.ResetAllProperties());
engine.Stub(action => action.Manufacturing.ResetAllProperties());
// Act
status.ResetAllProperties();
// Assert
engine.AssertWasCalled(action => action.Location.ResetAllProperties());
engine.AssertWasCalled(action => action.Manufacturing.ResetAllProperties());
}
}
}
You are asserting the behaviour of Location and Manufacturing, so these are the objects which should be mocked. Also, when checking that something happens use Expects not Stub. Everything else should be concrete. If you make ResetAllProperties methods virtual then the following works:
[TestMethod]
public void ResetAllProperties_AssertWasCalled()
{
var location = MockRepository.GeneratePartialMock<EngineLocation>();
var manufacturing = MockRepository.GeneratePartialMock<EngineManufacturing>();
// Arrange
var engine = new Engine
{
Location = location,
Manufacturing = manufacturing
};
var status = new FirstEngineStatus(engine);
location.Expect(action => action.ResetAllProperties());
manufacturing.Expect(action => action.ResetAllProperties());
// Act
status.ResetAllProperties();
// Assert
location.VerifyAllExpectations();
manufacturing.VerifyAllExpectations();
}
However, this seems like you are testing the implementation rather than the functionality. What do you actually want to test? It looks to me like you want to test that CustomerName and EntryDate are set to null. You can test this without using any mocking at all as follows:
[TestMethod]
public void ResetAllProperties_AssertWasCalled()
{
// Arrange
var engine = new Engine
{
Location = new EngineLocation { CustomerName = "Dzenan" },
Manufacturing = new EngineManufacturing { EntryDate = DateTime.Today }
};
var status = new FirstEngineStatus(engine);
// Act
status.ResetAllProperties();
// Assert
Assert.IsNull(engine.Location.CustomerName);
Assert.IsNull(engine.Manufacturing.EntryDate);
}
I have a test method...
[TestMethod]
public void MainViewModel_PropertiesReflectDataEntityProperties()
{
// Arrange
var facilityDataEntity = MockRepository.GenerateStub<FacilityDataEntity>();
var shopOrderDataEntity = MockRepository.GenerateStub<ShopOrderDataEntity>();
// Act
MainViewModel mainViewModel = new MainViewModel(facilityDataEntity, shopOrderDataEntity);
// Assert
Assert.AreSame(facilityDataEntity.Value, mainViewModel.FacilityValue);
}
... and the test passes. However, I have not implemented the mapping of the DataEntity's properties to the MainViewModel's properties yet! How can this be? I thought AreSame checks whether two references point to the same instance.
public class MainViewModel
{
private readonly FacilityDataEntity facilityDataEntity;
private readonly ShopOrderDataEntity shopOrderDataEntity;
public MainViewModel(FacilityDataEntity facilityDataEntity)
{
this.facilityDataEntity = facilityDataEntity;
}
public MainViewModel(FacilityDataEntity facilityDataEntity, ShopOrderDataEntity shopOrderDataEntity)
{
this.facilityDataEntity = facilityDataEntity;
this.shopOrderDataEntity = shopOrderDataEntity;
}
public ShopOrderDataEntity ShopOrderDataEntity
{
get { return shopOrderDataEntity; }
}
public FacilityDataEntity FacilityDataEntity
{
get { return facilityDataEntity; }
}
public int ShopOrder { get; set; }
public decimal RequiredQuantity { get; set; }
public string ItemCode { get; set; }
public string ItemDescription { get; set; }
public string FacilityValue { get; set; }
public string FacilityLabel { get; set; }
public static IEnumerable<MainViewModel> TranslateDataEntityList(IEnumerable<FacilityDataEntity> facilityDataEntityList)
{
foreach (FacilityDataEntity facilityDataEntity in facilityDataEntityList)
{
yield return new MainViewModel(facilityDataEntity);
}
}
public static IEnumerable<MainViewModel> TranslateDataEntityList(FacilityDataEntity facilityDataEntity, IEnumerable<ShopOrderDataEntity> shopOrderDataEntityList)
{
foreach (ShopOrderDataEntity shopOrderDataEntity in shopOrderDataEntityList)
{
yield return new MainViewModel(facilityDataEntity, shopOrderDataEntity);
}
}
}
Underneath it all, these tests are just using Object.ReferenceEquals:
true if objA is the same instance as objB or if both are null; otherwise, false.
I guess this is happening because they are both null.
in this case, I'd say its comparing null with null, which are the same.
I have implemented Single Pattern. Here is my code i am getting the an error when i call the Test.BuildData() function. Please help
public class WordDataItem
{
public string Word { get; set; }
public string Definition { get; set; }
public int WordGroupKey { get; set; }
}
public class WordDataGroup
{
public List<WordDataItem> listItem = new List<WordDataItem>();
public int GroupKey { get; set; }
}
public sealed class WordDataSource
{
private static WordDataSource _dataSoruce;
private List<WordDataGroup> listGroup = new List<WordDataGroup>();
public List<WordDataGroup> ListGroup
{
get { return listGroup; }
set { listGroup = value; }
}
private WordDataSource() { }
public static WordDataSource Instance
{
get
{
if (Instance == null)
{
_dataSoruce = new WordDataSource();
}
return _dataSoruce;
}
}
}
public static class Test
{
public static void BuildData()
{
WordDataSource.Instance.ListGroup.Add(new WordDataGroup() { GroupKey = 8, listItem = new List<WordDataItem>() { new WordDataItem() {Word = "Hello", Definition="Greetings", WordGroupKey = 8}} });
}
}
I get an error of stack over flow when i call the Test.BuildData() function.
Your Instance property is recursively calling into itself when you check if it is null.
Try this:
public static WordDataSource Instance
{
get
{
if (_dataSoruce == null)
{
_dataSoruce = new WordDataSource();
}
return _dataSoruce;
}
}
Here is code:
public interface IAccessPoint
{
int BackHaulMaximum { get; set; }
bool BackHaulMaximumReached();
void EmailNetworkProvider();
}
public class AccessPoint : IAccessPoint
{
private IMailProvider Mailer { get; set; }
public AccessPoint(IMailProvider provider)
{
this.Mailer = provider ?? new DefaultMailProvider();
}
public int BackHaulMaximum { get; set; }
public bool BackHaulMaximumReached()
{
if (BackHaulMaximum > 80)
{
EmailNetworkProvider();
return true;
}
return false;
}
public void EmailNetworkProvider()
{
this.Mailer.SendMail();
}
}
public interface IMailProvider
{
void SendMail();
}
public class DefaultMailProvider : IMailProvider
{
public void SendMail()
{
}
}
// Here is the Test, It is not calling EmailNetworkProvider which calls SendMail()
[TestFixture]
public class Tests
{
[Test]
public void NetworkProviderShouldBeEmailedWhenBackHaulMaximumIsReached()
{
var mailerMock = MockRepository.GenerateMock<IMailProvider>();
mailerMock.Expect(x => x.SendMail());
var accessPoint = new AccessPoint(mailerMock);
accessPoint.BackHaulMaximum = 81;
Assert.IsTrue(accessPoint.BackHaulMaximumReached());
mailerMock.VerifyAllExpectations();
}
}
Any improvement if you use this test?
[Test]
public void NetworkProviderShouldBeEmailedWhenBackHaulMaximumIsReached()
{
var mailerMock = MockRepository.GenerateStub<IMailProvider>();
var accessPoint = new AccessPoint(mailerMock);
accessPoint.BackHaulMaximum = 81;
var actual = accessPoint.BackHaulMaximumReached();
Assert.AreEqual(true, actual);
mailerMock.AssertWasCalled(x => x.SendMail());
}
As a side-note, BackhaulMaximumReached() is kind of a bizarre design. No notification will be made unless a consumer checks whether the back haul maximum was reached, regardless of the value of BackHaulMaximum.
It is semantically confusing to comingle commands and queries in this way.