For example you are testing getSomeString
.
public class Class1
{
public Class1() {}
public string getSomeString(string input)
{
//dosomething
OtherClass class = new OtherClass();
return class.getData();
}
}
public class OtherClass
{
public OtherClass() {/*some data*/}
public string getData()
{
//do something
string aString = getAString(Input);
//do something
}
public virtual string getAString(string input);
{
//do something to be mocked
return somethingToBeMocked;
}
}
So you need the unit test to mock out getAString
. How do you do this?
I have tried just mocking getAString
and hoping the test uses the mocked value, but that doesn't work.
I have tried mocking Class1
and setting the unit test class1
to be the mocked object, but I could not figure out how to make the mocked getAString
passed into the mocked class1
.
I cannot figure out what to do.
You can't just take any code and unit test it. Code should be testable. What is testable code? It's a code which depends on abstractions instead of implementations. Only way to avoid depending on implementations is providing them via dependency injection:
public class Class1()
{
private IOtherClass _otherClass; // depend on this abstraction
public Class1(IOtherClass otherClass) // constructor injection
{
_otherClass = otherClass;
}
public string getSomeString(string input)
{
//dosomething
return _otherClass.getData(); // you don't know implementation
}
}
Where IOtherClass
interface is implemented by OtherClass
public interface IOtherClass
{
string getData();
}
Now your class depends on abstraction and you can mock abstraction for tests:
string data = "Foo";
Mock<IOtherClass> otherClassMock = new Mock<IOtherClass>();
otherClassMock.Setup(oc => oc.getData()).Returns(data);
var class1 = new Class1(otherClassMock.Object);
// Act
string result = class1.getSomeString("Bar");
// Assert
Assert.That(result, Is.EqualTo(data));
otherClassMock.VerifyAll(); // check dependency was called
The way you typically accomplish this is by coding to an interface and then injecting an implementation into the class you're trying to test.
In this case, your public API to OtherClass
looks like it's really just one method: getData()
. So, with that in mind:
public class Class1
{
private IOtherClass otherClass;
public Class1(IOtherClass otherClass)
{
this.otherClass = otherClass;
}
public string getSomeString(string input)
{
return otherClass.getData();
}
}
public interface IOtherClass
{
string getData();
}
public class OtherClass : IOtherClass
{
public Otherclass() {/*some data*/}
public string getData()
{
//do something
string aString = getAString(Input);
//do something
}
private string getAString(string input);
{
//do something to be mocked
return somethingToBeMocked;
}
}
Then, when you wanted to mock, you create a fake implementation of IOtherClass
and provide it to Class1
.
I haven't used Moq for a while, but you should be able to do something like this in your test:
[TestMethod]
public void Foo()
{
//Arrange
var expected = "expectedResult";
var mock = new Mock<IOtherClass>();
var otherClass = mock.Setup(foo => foo.getData()).Returns("someValue");
var myClass = new Class1(otherClass.Object);
//Act
var actual = myClass.getSomeString("something");
//Assert
Assert.AreEqual(expected, actual);
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.